diff --git a/.bazelrc b/.bazelrc index 2505bbfdf44f0c..524542a02a4aa9 100644 --- a/.bazelrc +++ b/.bazelrc @@ -2,12 +2,13 @@ # Import shared settings first so we can override below import %workspace%/.bazelrc.common -## Disabled for now # Remote cache settings for local env -# build --remote_cache=https://storage.googleapis.com/kibana-bazel-cache -# build --incompatible_remote_results_ignore_disk=true -# build --remote_accept_cached=true -# build --remote_upload_local_results=false +build --remote_cache=grpcs://cloud.buildbuddy.io +build --incompatible_remote_results_ignore_disk=true +build --noremote_upload_local_results +build --remote_timeout=30 +build --remote_header=x-buildbuddy-api-key=3EYk49W2NefOx2n3yMze +build --remote_accept_cached=true # BuildBuddy ## Metadata settings diff --git a/.buildkite/scripts/common/setup_bazel.sh b/.buildkite/scripts/common/setup_bazel.sh old mode 100644 new mode 100755 diff --git a/.buildkite/scripts/lifecycle/pre_command.sh b/.buildkite/scripts/lifecycle/pre_command.sh index 54ed8d575b5e08..be31bb74ef6688 100755 --- a/.buildkite/scripts/lifecycle/pre_command.sh +++ b/.buildkite/scripts/lifecycle/pre_command.sh @@ -89,7 +89,6 @@ if [[ "${SKIP_CI_SETUP:-}" != "true" ]]; then if [[ -d .buildkite/scripts && "${BUILDKITE_COMMAND:-}" != "buildkite-agent pipeline upload"* ]]; then source .buildkite/scripts/common/env.sh source .buildkite/scripts/common/setup_node.sh - source .buildkite/scripts/common/setup_bazel.sh fi fi diff --git a/.buildkite/scripts/steps/on_merge_build_and_metrics.sh b/.buildkite/scripts/steps/on_merge_build_and_metrics.sh index 1f1e492f87bec0..b24e585e707354 100755 --- a/.buildkite/scripts/steps/on_merge_build_and_metrics.sh +++ b/.buildkite/scripts/steps/on_merge_build_and_metrics.sh @@ -2,6 +2,9 @@ set -euo pipefail +# Write Bazel cache for Linux +.buildkite/scripts/common/setup_bazel.sh + .buildkite/scripts/bootstrap.sh .buildkite/scripts/build_kibana.sh .buildkite/scripts/post_build_kibana.sh diff --git a/.eslintrc.js b/.eslintrc.js index 7e865cd99a6d3e..f45088f046bdd6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1595,7 +1595,6 @@ module.exports = { */ { files: [ - 'src/plugins/security_oss/**/*.{js,mjs,ts,tsx}', 'src/plugins/interactive_setup/**/*.{js,mjs,ts,tsx}', 'x-pack/plugins/encrypted_saved_objects/**/*.{js,mjs,ts,tsx}', 'x-pack/plugins/security/**/*.{js,mjs,ts,tsx}', diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 244689025173f5..17150e3c98cec1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -39,6 +39,7 @@ /src/plugins/visualize/ @elastic/kibana-vis-editors /src/plugins/visualizations/ @elastic/kibana-vis-editors /src/plugins/chart_expressions/expression_tagcloud/ @elastic/kibana-vis-editors +/src/plugins/chart_expressions/expression_metric/ @elastic/kibana-vis-editors /src/plugins/url_forwarding/ @elastic/kibana-vis-editors /packages/kbn-tinymath/ @elastic/kibana-vis-editors /x-pack/test/functional/apps/lens @elastic/kibana-vis-editors @@ -287,9 +288,7 @@ # Security /src/core/server/csp/ @elastic/kibana-security @elastic/kibana-core -/src/plugins/security_oss/ @elastic/kibana-security /src/plugins/interactive_setup/ @elastic/kibana-security -/test/security_functional/ @elastic/kibana-security /x-pack/plugins/spaces/ @elastic/kibana-security /x-pack/plugins/encrypted_saved_objects/ @elastic/kibana-security /x-pack/plugins/security/ @elastic/kibana-security diff --git a/.i18nrc.json b/.i18nrc.json index 46d2f8c6a23bf2..63e4cf6d2fbb9b 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -30,6 +30,7 @@ "expressionRevealImage": "src/plugins/expression_reveal_image", "expressionShape": "src/plugins/expression_shape", "expressionTagcloud": "src/plugins/chart_expressions/expression_tagcloud", + "expressionMetricVis": "src/plugins/chart_expressions/expression_metric", "inputControl": "src/plugins/input_control_vis", "inspector": "src/plugins/inspector", "inspectorViews": "src/legacy/core_plugins/inspector_views", @@ -55,7 +56,6 @@ "newsfeed": "src/plugins/newsfeed", "savedObjects": "src/plugins/saved_objects", "savedObjectsManagement": "src/plugins/saved_objects_management", - "security": "src/plugins/security_oss", "server": "src/legacy/server", "statusPage": "src/legacy/core_plugins/status_page", "telemetry": ["src/plugins/telemetry", "src/plugins/telemetry_management_section"], diff --git a/api_docs/charts.json b/api_docs/charts.json index 642ae89e581e58..9f6d07287eba18 100644 --- a/api_docs/charts.json +++ b/api_docs/charts.json @@ -478,7 +478,7 @@ "signature": [ "(value: any, colorSchemaName: string) => string" ], - "path": "src/plugins/charts/public/static/color_maps/heatmap_color.ts", + "path": "src/plugins/charts/common/static/color_maps/heatmap_color.ts", "deprecated": false, "children": [ { @@ -491,7 +491,7 @@ "signature": [ "any" ], - "path": "src/plugins/charts/public/static/color_maps/heatmap_color.ts", + "path": "src/plugins/charts/common/static/color_maps/heatmap_color.ts", "deprecated": false, "isRequired": true }, @@ -505,7 +505,7 @@ "signature": [ "string" ], - "path": "src/plugins/charts/public/static/color_maps/heatmap_color.ts", + "path": "src/plugins/charts/common/static/color_maps/heatmap_color.ts", "deprecated": false, "isRequired": true } @@ -936,7 +936,7 @@ "tags": [], "label": "ColorMap", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false, "children": [ { @@ -949,7 +949,7 @@ "signature": [ "any" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false } ], @@ -962,7 +962,7 @@ "tags": [], "label": "ColorSchema", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false, "children": [ { @@ -981,7 +981,7 @@ "text": "ColorSchemas" } ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -991,7 +991,7 @@ "tags": [], "label": "text", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false } ], @@ -1817,7 +1817,7 @@ "tags": [], "label": "RawColorSchema", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false, "children": [ { @@ -1836,7 +1836,7 @@ "text": "ColorSchemas" } ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -1846,7 +1846,7 @@ "tags": [], "label": "label", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -1859,7 +1859,7 @@ "signature": [ "[number, number[]][]" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false } ], @@ -2011,7 +2011,7 @@ "tags": [], "label": "ColorSchemas", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false, "initialIsOpen": false } @@ -2027,7 +2027,7 @@ "signature": [ "\"Background\" | \"Labels\" | \"None\"" ], - "path": "src/plugins/charts/public/static/components/collections.ts", + "path": "src/plugins/charts/common/static/components/collections.ts", "deprecated": false, "initialIsOpen": false }, @@ -2048,7 +2048,7 @@ }, "[]" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false, "initialIsOpen": false }, @@ -2059,7 +2059,7 @@ "tags": [], "label": "defaultCountLabel", "description": [], - "path": "src/plugins/charts/public/static/components/collections.ts", + "path": "src/plugins/charts/common/static/components/collections.ts", "deprecated": false, "initialIsOpen": false }, @@ -2073,7 +2073,7 @@ "signature": [ "number" ], - "path": "src/plugins/charts/public/static/components/collections.ts", + "path": "src/plugins/charts/common/static/components/collections.ts", "deprecated": false, "initialIsOpen": false }, @@ -2124,7 +2124,7 @@ }, "[]" ], - "path": "src/plugins/charts/public/static/color_maps/truncated_color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/truncated_color_maps.ts", "deprecated": false, "initialIsOpen": false } @@ -2140,7 +2140,7 @@ "signature": [ "{ readonly Background: \"Background\"; readonly Labels: \"Labels\"; readonly None: \"None\"; }" ], - "path": "src/plugins/charts/public/static/components/collections.ts", + "path": "src/plugins/charts/common/static/components/collections.ts", "deprecated": false, "initialIsOpen": false }, @@ -2154,7 +2154,7 @@ "signature": [ "{ readonly Horizontal: number; readonly Vertical: number; readonly Angled: number; }" ], - "path": "src/plugins/charts/public/static/components/collections.ts", + "path": "src/plugins/charts/common/static/components/collections.ts", "deprecated": false, "initialIsOpen": false }, @@ -2165,7 +2165,7 @@ "tags": [], "label": "truncatedColorMaps", "description": [], - "path": "src/plugins/charts/public/static/color_maps/truncated_color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/truncated_color_maps.ts", "deprecated": false, "children": [], "initialIsOpen": false @@ -2177,7 +2177,7 @@ "tags": [], "label": "vislibColorMaps", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false, "children": [ { @@ -2189,7 +2189,7 @@ "description": [ "// Sequential" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false, "children": [ { @@ -2209,7 +2209,7 @@ }, ".Blues" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -2219,7 +2219,7 @@ "tags": [], "label": "label", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -2232,7 +2232,7 @@ "signature": [ "[number, number[]][]" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false } ] @@ -2244,7 +2244,7 @@ "tags": [], "label": "[ColorSchemas.Greens]", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false, "children": [ { @@ -2264,7 +2264,7 @@ }, ".Greens" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -2274,7 +2274,7 @@ "tags": [], "label": "label", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -2287,7 +2287,7 @@ "signature": [ "[number, number[]][]" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false } ] @@ -2299,7 +2299,7 @@ "tags": [], "label": "[ColorSchemas.Greys]", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false, "children": [ { @@ -2319,7 +2319,7 @@ }, ".Greys" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -2329,7 +2329,7 @@ "tags": [], "label": "label", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -2342,7 +2342,7 @@ "signature": [ "[number, number[]][]" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false } ] @@ -2354,7 +2354,7 @@ "tags": [], "label": "[ColorSchemas.Reds]", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false, "children": [ { @@ -2374,7 +2374,7 @@ }, ".Reds" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -2384,7 +2384,7 @@ "tags": [], "label": "label", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -2397,7 +2397,7 @@ "signature": [ "[number, number[]][]" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false } ] @@ -2409,7 +2409,7 @@ "tags": [], "label": "[ColorSchemas.YellowToRed]", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false, "children": [ { @@ -2429,7 +2429,7 @@ }, ".YellowToRed" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -2439,7 +2439,7 @@ "tags": [], "label": "label", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -2452,7 +2452,7 @@ "signature": [ "[number, number[]][]" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false } ] @@ -2464,7 +2464,7 @@ "tags": [], "label": "[ColorSchemas.GreenToRed]", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false, "children": [ { @@ -2484,7 +2484,7 @@ }, ".GreenToRed" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -2494,7 +2494,7 @@ "tags": [], "label": "label", "description": [], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false }, { @@ -2507,7 +2507,7 @@ "signature": [ "[number, number[]][]" ], - "path": "src/plugins/charts/public/static/color_maps/color_maps.ts", + "path": "src/plugins/charts/common/static/color_maps/color_maps.ts", "deprecated": false } ] diff --git a/api_docs/security_oss.json b/api_docs/security_oss.json deleted file mode 100644 index 601563752d47dc..00000000000000 --- a/api_docs/security_oss.json +++ /dev/null @@ -1,203 +0,0 @@ -{ - "id": "securityOss", - "client": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [], - "setup": { - "parentPluginId": "securityOss", - "id": "def-public.SecurityOssPluginSetup", - "type": "Interface", - "tags": [], - "label": "SecurityOssPluginSetup", - "description": [], - "path": "src/plugins/security_oss/public/plugin.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "securityOss", - "id": "def-public.SecurityOssPluginSetup.insecureCluster", - "type": "Object", - "tags": [], - "label": "insecureCluster", - "description": [], - "signature": [ - "InsecureClusterServiceSetup" - ], - "path": "src/plugins/security_oss/public/plugin.ts", - "deprecated": false - } - ], - "lifecycle": "setup", - "initialIsOpen": true - }, - "start": { - "parentPluginId": "securityOss", - "id": "def-public.SecurityOssPluginStart", - "type": "Interface", - "tags": [], - "label": "SecurityOssPluginStart", - "description": [], - "path": "src/plugins/security_oss/public/plugin.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "securityOss", - "id": "def-public.SecurityOssPluginStart.insecureCluster", - "type": "Object", - "tags": [], - "label": "insecureCluster", - "description": [], - "signature": [ - "InsecureClusterServiceStart" - ], - "path": "src/plugins/security_oss/public/plugin.ts", - "deprecated": false - }, - { - "parentPluginId": "securityOss", - "id": "def-public.SecurityOssPluginStart.anonymousAccess", - "type": "Object", - "tags": [], - "label": "anonymousAccess", - "description": [], - "signature": [ - "{ getAccessURLParameters: () => Promise | null>; getCapabilities: () => Promise<", - "Capabilities", - ">; }" - ], - "path": "src/plugins/security_oss/public/plugin.ts", - "deprecated": false - } - ], - "lifecycle": "start", - "initialIsOpen": true - } - }, - "server": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [], - "setup": { - "parentPluginId": "securityOss", - "id": "def-server.SecurityOssPluginSetup", - "type": "Interface", - "tags": [], - "label": "SecurityOssPluginSetup", - "description": [], - "path": "src/plugins/security_oss/server/plugin.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "securityOss", - "id": "def-server.SecurityOssPluginSetup.showInsecureClusterWarning$", - "type": "Object", - "tags": [], - "label": "showInsecureClusterWarning$", - "description": [ - "\nAllows consumers to show/hide the insecure cluster warning." - ], - "signature": [ - "BehaviorSubject", - "" - ], - "path": "src/plugins/security_oss/server/plugin.ts", - "deprecated": false - }, - { - "parentPluginId": "securityOss", - "id": "def-server.SecurityOssPluginSetup.setAnonymousAccessServiceProvider", - "type": "Function", - "tags": [], - "label": "setAnonymousAccessServiceProvider", - "description": [ - "\nSet the provider function that returns a service to deal with the anonymous access." - ], - "signature": [ - "(provider: () => ", - "AnonymousAccessService", - ") => void" - ], - "path": "src/plugins/security_oss/server/plugin.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "securityOss", - "id": "def-server.SecurityOssPluginSetup.setAnonymousAccessServiceProvider.$1", - "type": "Function", - "tags": [], - "label": "provider", - "description": [], - "signature": [ - "() => ", - "AnonymousAccessService" - ], - "path": "src/plugins/security_oss/server/plugin.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - } - ], - "lifecycle": "setup", - "initialIsOpen": true - } - }, - "common": { - "classes": [], - "functions": [], - "interfaces": [ - { - "parentPluginId": "securityOss", - "id": "def-common.AppState", - "type": "Interface", - "tags": [], - "label": "AppState", - "description": [ - "\nDefines Security OSS application state." - ], - "path": "src/plugins/security_oss/common/app_state.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "securityOss", - "id": "def-common.AppState.insecureClusterAlert", - "type": "Object", - "tags": [], - "label": "insecureClusterAlert", - "description": [], - "signature": [ - "{ displayAlert: boolean; }" - ], - "path": "src/plugins/security_oss/common/app_state.ts", - "deprecated": false - }, - { - "parentPluginId": "securityOss", - "id": "def-common.AppState.anonymousAccess", - "type": "Object", - "tags": [], - "label": "anonymousAccess", - "description": [], - "signature": [ - "{ isEnabled: boolean; accessURLParameters: Record | null; }" - ], - "path": "src/plugins/security_oss/common/app_state.ts", - "deprecated": false - } - ], - "initialIsOpen": false - } - ], - "enums": [], - "misc": [], - "objects": [] - } -} \ No newline at end of file diff --git a/api_docs/security_oss.mdx b/api_docs/security_oss.mdx deleted file mode 100644 index 4cd5bc2a76135e..00000000000000 --- a/api_docs/security_oss.mdx +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: kibSecurityOssPluginApi -slug: /kibana-dev-docs/api/securityOss -title: "securityOss" -image: https://source.unsplash.com/400x175/?github -summary: API docs for the securityOss plugin -date: 2020-11-16 -tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securityOss'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. ---- -import securityOssObj from './security_oss.json'; - -This plugin exposes a limited set of security functionality to OSS plugins. - -Contact [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) for questions regarding this plugin. - -**Code health stats** - -| Public API count | Any count | Items lacking comments | Missing exports | -|-------------------|-----------|------------------------|-----------------| -| 12 | 0 | 9 | 3 | - -## Client - -### Setup - - -### Start - - -## Server - -### Setup - - -## Common - -### Interfaces - - diff --git a/dev_docs/api_welcome.mdx b/dev_docs/api_welcome.mdx index 00d5bfb9644afd..4dd0a1484c850b 100644 --- a/dev_docs/api_welcome.mdx +++ b/dev_docs/api_welcome.mdx @@ -58,7 +58,7 @@ type Bar = { id: string }; export type Foo = Bar | string; ``` -`Bar`, in the signature of `Foo`, will not be clickable because it would result in a broken link. `Bar` is not publically exported! +`Bar`, in the signature of `Foo`, will not be clickable because it would result in a broken link. `Bar` is not publicly exported! If that isn't the case, please file an issue, it could be a bug with the system. diff --git a/dev_docs/contributing/best_practices.mdx b/dev_docs/contributing/best_practices.mdx index 284baababfc666..7b72661c3dfd35 100644 --- a/dev_docs/contributing/best_practices.mdx +++ b/dev_docs/contributing/best_practices.mdx @@ -196,7 +196,7 @@ Over-refactoring can be a problem in it's own right, but it's still important to Try not to put your PR in review mode, or merge large changes, right before Feature Freeze. It's inevitably one of the most volatile times for the Kibana code base, try not to contribute to this volatility. Doing this can: -- increase the likelyhood of conflicts from other features being merged at the last minute +- increase the likelihood of conflicts from other features being merged at the last minute - means your feature has less QA time - means your feature gets less careful review as reviewers are often swamped at this time diff --git a/dev_docs/contributing/code_walkthrough.mdx b/dev_docs/contributing/code_walkthrough.mdx new file mode 100644 index 00000000000000..47eb05a95c424e --- /dev/null +++ b/dev_docs/contributing/code_walkthrough.mdx @@ -0,0 +1,139 @@ +--- +id: kibRepoStructure +slug: /kibana-dev-docs/contributing/repo-structure +title: Repository structure +summary: High level walk-through of our repository structure. +date: 2021-10-07 +tags: ['contributor', 'dev', 'github', 'getting started', 'onboarding', 'kibana'] +--- + +A high-level walk through of the folder structure of our [repository](https://github.com/elastic/kibana). + +Tip: Look for a `README.md` in a folder to learn about its contents. + +## [.buildkite](https://github.com/elastic/kibana/tree/master/.buildkite) + +Managed by the operations team to set up a new buildkite ci system. Can be ignored by folks outside the Operations team. + +## [.ci](https://github.com/elastic/kibana/tree/master/.ci) + +Managed by the operations team to contain Jenkins settings. Can be ignored by folks outside the Operations team. + +## [.github](https://github.com/elastic/kibana/tree/master/.github) + +Contains GitHub configuration settings. This file contains issue templates, and the [CODEOWNERS](https://github.com/elastic/kibana/blob/master/.github/CODEOWNERS) file. It's important for teams to keep the CODEOWNERS file up-to-date so the right team is pinged for a code owner review on PRs that edit certain files. Note that the `CODEOWNERS` file only exists on the main/master branch, and is not backported to other branches in the repo. + +## [api_docs](https://github.com/elastic/kibana/tree/master/api_docs) + +Every file in here is auto-generated by the and used to render our API documentation. If you edit a public plugin or package API and run `node scripts/build_api_docs` you will see files changed in this folder. Do not edit the contents of this folder directly! + +Note that currently you may see _a lot_ of changes because that command is not run on every PR and so the content in this folder is often outdated. + +## [config](https://github.com/elastic/kibana/tree/master/config) + +This contains the base configuration file, `kibana.yml`. If you want to tweak any settings, create a `kibana.dev.yml` in here which will get picked up during development, and not checked into GitHub. + +## [docs](https://github.com/elastic/kibana/tree/master/docs) + +Every folder in here _except_ the [development one](https://github.com/elastic/kibana/tree/master/docs/development) contains manually generated asciidocs that end up hosted in our [Elastic guide](https://www.elastic.co/guide/). + +The `development` folder contains markdown that is auto-generated with our legacy API docs tool. We are aiming to remove it shortly after 8.0FF. + +## [dev_docs](https://github.com/elastic/kibana/tree/master/dev_docs) + +This is where a lot of manually written content for our Developer Guide resides. Developers may also keep the information closer to what it's describing, but it's a good spot for high-level information, or information that describes how multiple plugins work together. + +## [examples](https://github.com/elastic/kibana/tree/master/examples) + +These are our tested example plugins that also get built and hosted [here](https://demo.kibana.dev/8.0/app/developerExamples). If a plugin is written for testing purposes only, it won't go in here. These example plugins should be written with the intention of helping developers understand how to use our services. + +## [legacy_rfcs](https://github.com/elastic/kibana/tree/master/legacy_rfcs) + +We used to write RFCs in `md` format and keep them in the repository, but we have since moved to Google Docs. We kept the folder around, since some folks still read these old docs. If you are an internal contributor you can visit to read about our current RFC process. + +## [licenses](https://github.com/elastic/kibana/tree/master/licenses) + +Contains our two license header texts, one for the Elastic license and one for the Elastic+SSPL license. All code files inside x-pack should have the Elastic license text at the top, all code files outside x-pack should contain the other. If you have your environment set up to auto-fix on save, eslint should take care of adding it for you. If you don't have it, ci will fail. Can be ignored for the most part, this rarely changes. + +## [packages](https://github.com/elastic/kibana/tree/master/packages) + +The packages folder contains a mixture of build-time related code (like the [code needed to build the api docs](https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils)), as well as static code that some plugins rely on (like the [kbn-monaco package](https://github.com/elastic/kibana/tree/master/packages/kbn-monaco)). covers how packages differ from plugins. + +## [plugins](https://github.com/elastic/kibana/tree/master/plugins) + +This is an empty folder in GitHub. It's where third party developers should put their plugin folders. Internal developers can ignore this folder. + +## [scripts](https://github.com/elastic/kibana/tree/master/scripts) + +Contains a bunch of developer scripts. These are usually very small files with just two lines that kick off a command, the logic of which resides elsewhere (sometimes `src/dev`, sometimes inside `packages`). +Example: +``` +require('../src/setup_node_env'); +require('@kbn/es-archiver').runCli(); +``` + +## [src](https://github.com/elastic/kibana/tree/master/src) + +This folder and the packages folder contain the most code and where developers usually find themselves. I'll touch on a few of the subfolder, the rest can generally be ignored, or are build/ops related code. + +### [src/cli*](https://github.com/elastic/kibana/tree/master/src/cli) + +Maintained primarily by the Operations team, this folder contains code that initializes the Kibana runtime and a bit of work to handle authorization for interactive setup mode. Most devs should be able to ignore this code. + +### [src/core](https://github.com/elastic/kibana/tree/master/src/core) + +This code primarily belongs to the Core team and contains the plugin infrastructure, as well as a bunch of fundamental services like migrations, saved objects, and some UI utilities (toasts, flyouts, etc.). + +### [src/dev](https://github.com/elastic/kibana/tree/master/src/dev) + +Maintained by the Operations team, this code contains build and development tooling related code. This folder existed before `packages`, so contains mostly older code that hasn't been migrated to packages. Prefer creating a `package` if possible. Can be ignored for the most part if you are not on the Ops team. Prefer + +### [src/plugins](https://github.com/elastic/kibana/tree/master/src/plugins) + +Contains all of our Basic-licensed plugins. Most folders in this directory will contain `README.md` files explaining what they do. If there are none, you can look at the `owner.gitHub` field inside all `kibana.json`s that will tell you which team to get in touch with for questions. + +Note that as plugins can be nested, each folder in this directory may contain multiple plugins. + +## [test](https://github.com/elastic/kibana/tree/master/test) + +Contains functional tests and related FTR (functional test runner) code for the plugins inside `src/plugins`, although there is a push to move the tests to reside inside the plugins themselves. + +## [typings](https://github.com/elastic/kibana/tree/master/typings) + +Maintained by Ops and Core, this contains global typings for dependencies that do not provide their own types, or don't have types available via [DefinitelyTyped](https://definitelytyped.org). This directory is intended to be minimal; types should only be added here as a last resort. + +## [vars](https://github.com/elastic/kibana/tree/master/vars) + +A bunch of groovy scripts maintained by the Operations team. + +## [x-pack](https://github.com/elastic/kibana/tree/master/x-pack) + +Contains all code and infrasturcture that powers our gold+ (non-basic) features that are provided under a more restrictive license. + +### [x-pack/build_chromium](https://github.com/elastic/kibana/tree/master/x-pack/build_chromium) + +Maintained by the App Services UX team, this contains Reporting-related code for building Chromium in order to take server side screenshots. + +### [x-pack/dev-tools](https://github.com/elastic/kibana/tree/master/x-pack/dev-tools) + +Maintained by the Operations team. + +### [x-pack/examples](https://github.com/elastic/kibana/tree/master/x-pack/examples) + +Contains all example plugins that rely on gold+ features. + +### [x-pack/plugins](https://github.com/elastic/kibana/tree/master/x-pack/plugins) + +Contains code for all the plugins that power our gold+ features. + +### [x-pack/scripts](https://github.com/elastic/kibana/tree/master/x-pack/scripts) + +Maintained by the Ops team, this folder contains some scripts for running x-pack utilities, like the functional test runner that runs with a license higher than Basic. + +### [x-pack/test](https://github.com/elastic/kibana/tree/master/x-pack/test) + +Functional tests for our gold+ features. + + + + diff --git a/dev_docs/getting_started/setting_up_a_development_env.mdx b/dev_docs/getting_started/setting_up_a_development_env.mdx index 4338083b1bc8d0..ae994d6a018de8 100644 --- a/dev_docs/getting_started/setting_up_a_development_env.mdx +++ b/dev_docs/getting_started/setting_up_a_development_env.mdx @@ -44,7 +44,7 @@ Then, install the latest version of yarn using: npm install -g yarn ``` -Finally, boostrap Kibana and install all of the remaining dependencies: +Finally, bootstrap Kibana and install all of the remaining dependencies: ```sh yarn kbn bootstrap diff --git a/dev_docs/key_concepts/navigation.mdx b/dev_docs/key_concepts/navigation.mdx index 85b0fe8429a54e..27ba3db111411d 100644 --- a/dev_docs/key_concepts/navigation.mdx +++ b/dev_docs/key_concepts/navigation.mdx @@ -50,7 +50,7 @@ console.log(discoverUrl); // http://localhost:5601/bpr/s/space/app/discover const discoverUrlWithSomeState = core.http.basePath.prepend(`/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:'2020-09-10T11:39:50.203Z',to:'2020-09-10T11:40:20.249Z'))&_a=(columns:!(_source),filters:!(),index:'90943e30-9a47-11e8-b64d-95841ca0b247',interval:auto,query:(language:kuery,query:''),sort:!())`); ``` -Instead, each app should expose {kib-repo}tree/{branch}/src/plugins/share/common/url_service/locators/README.md[a locator]. +Instead, each app should expose [a locator](https://github.com/elastic/kibana/blob/master/src/plugins/share/common/url_service/locators/README.md). Other apps should use those locators for navigation or URL creation. ```tsx @@ -114,8 +114,7 @@ const MySPALink = () => As it would be too much boilerplate to do this for each link in your app, there is a handy wrapper that helps with it: [RedirectAppLinks](https://github.com/elastic/kibana/blob/master/src/plugins/kibana_react/public/app_links/redirect_app_link.tsx#L49). -[source,typescript jsx] ----- +```jsx const MyApp = () => {/*...*/} @@ -123,7 +122,7 @@ const MyApp = () => Go to Dashboard {/*...*/} ----- +``` ## Setting up internal app routing @@ -167,7 +166,7 @@ Common use-case for using `core`'s `ScopedHistory` directly: ## Syncing state with URL Historically Kibana apps store _a lot_ of application state in the URL. -The most common pattern that {kib} apps follow today is storing state in `_a` and `_g` query params in [rison](https://github.com/w33ble/rison-node#readme) format. +The most common pattern that Kibana apps follow today is storing state in `_a` and `_g` query params in [rison](https://github.com/w33ble/rison-node#readme) format. Those query params follow the convention: diff --git a/dev_docs/key_concepts/saved_objects.mdx b/dev_docs/key_concepts/saved_objects.mdx index 7fe66b9eab95cb..159e6e90a40378 100644 --- a/dev_docs/key_concepts/saved_objects.mdx +++ b/dev_docs/key_concepts/saved_objects.mdx @@ -33,7 +33,7 @@ all the "children" will be automatically included. However, when a "child" is ex ## Migrations and Backward compatibility -As your plugin evolves, you may need to change your Saved Object type in a breaking way (for example, changing the type of an attribtue, or removing +As your plugin evolves, you may need to change your Saved Object type in a breaking way (for example, changing the type of an attribute, or removing an attribute). If that happens, you should write a migration to upgrade the Saved Objects that existed prior to the change. . diff --git a/dev_docs/tutorials/data/search.mdx b/dev_docs/tutorials/data/search.mdx index 81080b0c274186..1585adbdd37bed 100644 --- a/dev_docs/tutorials/data/search.mdx +++ b/dev_docs/tutorials/data/search.mdx @@ -477,7 +477,7 @@ If you don't call `clear`, you will see a warning in the console while developin The last step of the integration is restoring an existing search session. The `searchSessionId` parameter and the rest of the restore state are passed into the application via the URL. Non-URL support is planned for future releases. -If you detect the presense of a `searchSessionId` parameter in the URL, call the `restore` method **instead** of calling `start`. The previous example would now become: +If you detect the presence of a `searchSessionId` parameter in the URL, call the `restore` method **instead** of calling `start`. The previous example would now become: ```ts function onSearchSessionConfigChange(searchSessionIdFromUrl?: string) { diff --git a/docs/api/spaces-management/copy_saved_objects.asciidoc b/docs/api/spaces-management/copy_saved_objects.asciidoc index 1dd9cc9734a52e..cf18af9b28a34e 100644 --- a/docs/api/spaces-management/copy_saved_objects.asciidoc +++ b/docs/api/spaces-management/copy_saved_objects.asciidoc @@ -58,7 +58,7 @@ You can request to overwrite any objects that already exist in the target space NOTE: This cannot be used with the `overwrite` option. `overwrite`:: - (Optional, boolean) When set to `true`, all conflicts are automatically overidden. When a saved object with a matching `type` and `id` + (Optional, boolean) When set to `true`, all conflicts are automatically overridden. When a saved object with a matching `type` and `id` exists in the target space, that version is replaced with the version from the source space. The default value is `false`. + NOTE: This cannot be used with the `createNewCopies` option. diff --git a/docs/developer/advanced/images/sharing-saved-objects-faq-multiple-deep-link-objects-1.png b/docs/developer/advanced/images/sharing-saved-objects-faq-multiple-deep-link-objects-1.png new file mode 100644 index 00000000000000..d0fd93574d2faf Binary files /dev/null and b/docs/developer/advanced/images/sharing-saved-objects-faq-multiple-deep-link-objects-1.png differ diff --git a/docs/developer/advanced/images/sharing-saved-objects-faq-multiple-deep-link-objects-2.png b/docs/developer/advanced/images/sharing-saved-objects-faq-multiple-deep-link-objects-2.png new file mode 100644 index 00000000000000..c959042ab8d532 Binary files /dev/null and b/docs/developer/advanced/images/sharing-saved-objects-faq-multiple-deep-link-objects-2.png differ diff --git a/docs/developer/advanced/images/sharing-saved-objects-step-3.png b/docs/developer/advanced/images/sharing-saved-objects-step-3.png index 92dd7ebfef88e0..482b5f4e93a4ab 100644 Binary files a/docs/developer/advanced/images/sharing-saved-objects-step-3.png and b/docs/developer/advanced/images/sharing-saved-objects-step-3.png differ diff --git a/docs/developer/advanced/sharing-saved-objects.asciidoc b/docs/developer/advanced/sharing-saved-objects.asciidoc index 06019735188aac..8a0373363e4734 100644 --- a/docs/developer/advanced/sharing-saved-objects.asciidoc +++ b/docs/developer/advanced/sharing-saved-objects.asciidoc @@ -235,9 +235,7 @@ export class MyPlugin implements Plugin<{}, {}, {}, PluginStartDeps> { if (spacesApi && resolveResult.outcome === 'aliasMatch') { // We found this object by a legacy URL alias from its old ID; redirect the user to the page with its new ID, preserving any URL hash const newObjectId = resolveResult.alias_target_id!; // This is always defined if outcome === 'aliasMatch' - const newPath = http.basePath.prepend( - `path/to/this/page/${newObjectId}${window.location.hash}` - ); + const newPath = `/this/page/${newObjectId}${window.location.hash}`; // Use the *local* path within this app (do not include the "/app/appId" prefix) await spacesApi.ui.redirectLegacyUrl(newPath, OBJECT_NOUN); return; } @@ -255,9 +253,7 @@ const getLegacyUrlConflictCallout = () => { // callout with a warning for the user, and provide a way for them to navigate to the other object. const currentObjectId = savedObject.id; const otherObjectId = resolveResult.alias_target_id!; // This is always defined if outcome === 'conflict' - const otherObjectPath = http.basePath.prepend( - `path/to/this/page/${otherObjectId}${window.location.hash}` - ); + const otherObjectPath = `/this/page/${otherObjectId}${window.location.hash}`; // Use the *local* path within this app (do not include the "/app/appId" prefix) return ( <> {spacesApi.ui.components.getLegacyUrlConflict({ @@ -391,6 +387,13 @@ These should be handled on a case-by-case basis at the plugin owner's discretion * Any "secondary" objects on the page may handle the outcomes differently. If the secondary object ID is not important (for example, it just functions as a page anchor), it may make more sense to ignore the different outcomes. If the secondary object _is_ important but it is not directly represented in the UI, it may make more sense to throw a descriptive error when a `'conflict'` outcome is encountered. + - Embeddables should use `spacesApi.ui.components.getEmbeddableLegacyUrlConflict` to render conflict errors: ++ +image::images/sharing-saved-objects-faq-multiple-deep-link-objects-1.png["Sharing Saved Objects embeddable legacy URL conflict"] +Viewing details shows the user how to disable the alias and fix the problem using the +<>: ++ +image::images/sharing-saved-objects-faq-multiple-deep-link-objects-2.png["Sharing Saved Objects embeddable legacy URL conflict (showing details)"] - If the secondary object is resolved by an external service (such as the index pattern service), the service should simply make the full outcome available to consumers. diff --git a/docs/developer/advanced/upgrading-nodejs.asciidoc b/docs/developer/advanced/upgrading-nodejs.asciidoc index 3827cb6e9aa7de..d426ec1a2c91cc 100644 --- a/docs/developer/advanced/upgrading-nodejs.asciidoc +++ b/docs/developer/advanced/upgrading-nodejs.asciidoc @@ -5,7 +5,7 @@ When running {kib} from source, you must have this version installed locally. The required version of Node.js is listed in several different files throughout the {kib} source code. -Theses files must be updated when upgrading Node.js: +These files must be updated when upgrading Node.js: - {kib-repo}blob/{branch}/.ci/Dockerfile[`.ci/Dockerfile`] - The version is specified in the `NODE_VERSION` constant. This is used to pull the relevant image from https://hub.docker.com/_/node[Docker Hub]. @@ -29,7 +29,7 @@ The following rules are not set in stone. Use best judgement when backporting. Currently version 7.11 and newer run Node.js 14, while 7.10 and older run Node.js 10. -Hence, upgrades to either Node.js 14 or Node.js 10 shold be done as separate PRs. +Hence, upgrades to either Node.js 14 or Node.js 10 should be done as separate PRs. ==== Node.js patch upgrades diff --git a/docs/developer/architecture/security/rbac.asciidoc b/docs/developer/architecture/security/rbac.asciidoc index 451e833651a709..bf75ec1715de09 100644 --- a/docs/developer/architecture/security/rbac.asciidoc +++ b/docs/developer/architecture/security/rbac.asciidoc @@ -104,6 +104,6 @@ Authorization: Basic foo_read_only_user password } ---------------------------------- -{es} checks if the user is granted a specific action. If the user is assigned a role that grants a privilege, {es} uses the <> definition to associate this with the actions, which makes authorizing users more intuitive and flexible programatically. +{es} checks if the user is granted a specific action. If the user is assigned a role that grants a privilege, {es} uses the <> definition to associate this with the actions, which makes authorizing users more intuitive and flexible programmatically. Once we have authorized the user to perform a specific action, we can execute the request using `callWithInternalUser`. diff --git a/docs/developer/best-practices/typescript.asciidoc b/docs/developer/best-practices/typescript.asciidoc index 6058cb4945e11c..2631ee717c3d5f 100644 --- a/docs/developer/best-practices/typescript.asciidoc +++ b/docs/developer/best-practices/typescript.asciidoc @@ -47,7 +47,7 @@ Additionally, in order to migrate into project refs, you also need to make sure "declarationMap": true }, "include": [ - // add all the folders containg files to be compiled + // add all the folders containing files to be compiled ], "references": [ { "path": "../../core/tsconfig.json" }, diff --git a/docs/developer/contributing/development-ci-metrics.asciidoc b/docs/developer/contributing/development-ci-metrics.asciidoc index 2efe4e7c60a7dc..3a133e64ea5286 100644 --- a/docs/developer/contributing/development-ci-metrics.asciidoc +++ b/docs/developer/contributing/development-ci-metrics.asciidoc @@ -67,7 +67,7 @@ You can report new metrics by using the `CiStatsReporter` class provided by the In order to prevent the page load bundles from growing unexpectedly large we limit the `page load asset size` metric for each plugin. When a PR increases this metric beyond the limit defined for that plugin in {kib-repo}blob/{branch}/packages/kbn-optimizer/limits.yml[`limits.yml`] a failed commit status is set and the PR author needs to decide how to resolve this issue before the PR can be merged. -In most cases the limit should be high enough that PRs shouldn't trigger overages, but when they do make sure it's clear what is cuasing the overage by trying the following: +In most cases the limit should be high enough that PRs shouldn't trigger overages, but when they do make sure it's clear what is causing the overage by trying the following: 1. Run the optimizer locally with the `--profile` flag to produce webpack `stats.json` files for bundles which can be inspected using a number of different online tools. Focus on the chunk named `{pluginId}.plugin.js`; the `*.chunk.js` chunks make up the `async chunks size` metric which is currently unlimited and is the main way that we <>. + @@ -107,7 +107,7 @@ prettier -w {pluginDir}/target/public/{pluginId}.plugin.js Once you've identified the files which were added to the build you likely just need to stick them behind an async import as described in <>. -In the case that the bundle size is not being bloated by anything obvious, but it's still larger than the limit, you can raise the limit in your PR. Do this either by editting the {kib-repo}blob/{branch}/packages/kbn-optimizer/limits.yml[`limits.yml` file] manually or by running the following to have the limit updated to the current size + 15kb +In the case that the bundle size is not being bloated by anything obvious, but it's still larger than the limit, you can raise the limit in your PR. Do this either by editing the {kib-repo}blob/{branch}/packages/kbn-optimizer/limits.yml[`limits.yml` file] manually or by running the following to have the limit updated to the current size + 15kb [source,shell] ----------- diff --git a/docs/developer/contributing/development-functional-tests.asciidoc b/docs/developer/contributing/development-functional-tests.asciidoc index 6f5c05f526bd6b..fb56acef0a0cc4 100644 --- a/docs/developer/contributing/development-functional-tests.asciidoc +++ b/docs/developer/contributing/development-functional-tests.asciidoc @@ -185,8 +185,8 @@ node scripts/functional_test_runner --config test/functional/config.firefox.js [discrete] ==== Using the test_user service -Tests should run at the positive security boundry condition, meaning that they should be run with the mimimum privileges required (and documented) and not as the superuser. - This prevents the type of regression where additional privleges accidentally become required to perform the same action. +Tests should run at the positive security boundary condition, meaning that they should be run with the minimum privileges required (and documented) and not as the superuser. + This prevents the type of regression where additional privileges accidentally become required to perform the same action. The functional UI tests now default to logging in with a user named `test_user` and the roles of this user can be changed dynamically without logging in and out. @@ -458,7 +458,7 @@ Bad example: `PageObjects.app.clickButton()` class AppPage { // what can people who call this method expect from the // UI after the promise resolves? Since the reaction to most - // clicks is asynchronous the behavior is dependant on timing + // clicks is asynchronous the behavior is dependent on timing // and likely to cause test that fail unexpectedly async clickButton () { await testSubjects.click(‘menuButton’); diff --git a/docs/developer/contributing/development-tests.asciidoc b/docs/developer/contributing/development-tests.asciidoc index 340e122b44c1b9..81ca46669a8283 100644 --- a/docs/developer/contributing/development-tests.asciidoc +++ b/docs/developer/contributing/development-tests.asciidoc @@ -51,7 +51,7 @@ Any additional options supplied to `test:jest` will be passed onto the Jest CLI ---- kibana/src/plugins/dashboard/server$ yarn test:jest --coverage -# is equivelant to +# is equivalent to yarn jest --coverage --verbose --config /home/tyler/elastic/kibana/src/plugins/dashboard/jest.config.js server ---- diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index cbf46801fa86fa..0e728a4dada240 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -94,6 +94,10 @@ This API doesn't support angular, for registering angular dev tools, bootstrap a |Expression Metric plugin adds a metric renderer and function to the expression plugin. +|{kib-repo}blob/{branch}/src/plugins/chart_expressions/expression_metric/README.md[expressionMetricVis] +|Expression MetricVis plugin adds a metric renderer and function to the expression plugin. The renderer will display the metric chart. + + |{kib-repo}blob/{branch}/src/plugins/expression_repeat_image/README.md[expressionRepeatImage] |Expression Repeat Image plugin adds a repeatImage function to the expression plugin and an associated renderer. The renderer will display the given image in mutliple instances. @@ -223,11 +227,6 @@ oss plugins. |The service exposed by this plugin informs consumers whether they should optimize for non-interactivity. In this way plugins can avoid loading unnecessary code, data or other services. -|{kib-repo}blob/{branch}/src/plugins/security_oss/README.md[securityOss] -|securityOss is responsible for educating users about Elastic's free security features, -so they can properly protect the data within their clusters. - - |{kib-repo}blob/{branch}/src/plugins/share/README.md[share] |The share plugin contains various utilities for displaying sharing context menu, generating deep links to other apps, and creating short URLs. diff --git a/docs/developer/plugin/migrating-legacy-plugins-examples.asciidoc b/docs/developer/plugin/migrating-legacy-plugins-examples.asciidoc index acc42ec91bb710..4636a40471e123 100644 --- a/docs/developer/plugin/migrating-legacy-plugins-examples.asciidoc +++ b/docs/developer/plugin/migrating-legacy-plugins-examples.asciidoc @@ -486,7 +486,7 @@ to change the application or the navlink state at runtime. [source,typescript] ---- -// my_plugin has a required dependencie to the `licensing` plugin +// my_plugin has a required dependency to the `licensing` plugin interface MyPluginSetupDeps { licensing: LicensingPluginSetup; } diff --git a/docs/development/core/public/kibana-plugin-core-public.appnavoptions.euiicontype.md b/docs/development/core/public/kibana-plugin-core-public.appnavoptions.euiicontype.md index 069eccf63a2351..ed9d07cd29861e 100644 --- a/docs/development/core/public/kibana-plugin-core-public.appnavoptions.euiicontype.md +++ b/docs/development/core/public/kibana-plugin-core-public.appnavoptions.euiicontype.md @@ -4,7 +4,7 @@ ## AppNavOptions.euiIconType property -A EUI iconType that will be used for the app's icon. This icon takes precendence over the `icon` property. +A EUI iconType that will be used for the app's icon. This icon takes precedence over the `icon` property. Signature: diff --git a/docs/development/core/public/kibana-plugin-core-public.appnavoptions.md b/docs/development/core/public/kibana-plugin-core-public.appnavoptions.md index 52c28c861dc704..cb5ae936988dc8 100644 --- a/docs/development/core/public/kibana-plugin-core-public.appnavoptions.md +++ b/docs/development/core/public/kibana-plugin-core-public.appnavoptions.md @@ -16,7 +16,7 @@ export interface AppNavOptions | Property | Type | Description | | --- | --- | --- | -| [euiIconType](./kibana-plugin-core-public.appnavoptions.euiicontype.md) | string | A EUI iconType that will be used for the app's icon. This icon takes precendence over the icon property. | +| [euiIconType](./kibana-plugin-core-public.appnavoptions.euiicontype.md) | string | A EUI iconType that will be used for the app's icon. This icon takes precedence over the icon property. | | [icon](./kibana-plugin-core-public.appnavoptions.icon.md) | string | A URL to an image file used as an icon. Used as a fallback if euiIconType is not provided. | | [order](./kibana-plugin-core-public.appnavoptions.order.md) | number | An ordinal used to sort nav links relative to one another for display. | | [tooltip](./kibana-plugin-core-public.appnavoptions.tooltip.md) | string | A tooltip shown when hovering over app link. | diff --git a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md index ab0f2d0ee5a17e..c8ccdfeedb83f7 100644 --- a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md +++ b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md @@ -143,6 +143,7 @@ readonly links: { readonly ruleChangeLog: string; readonly detectionsReq: string; readonly networkMap: string; + readonly troubleshootGaps: string; }; readonly query: { readonly eql: string; @@ -213,6 +214,10 @@ readonly links: { mappingRolesFieldRules: string; runAsPrivilege: string; }>; + readonly spaces: Readonly<{ + kibanaLegacyUrlAliases: string; + kibanaDisableLegacyUrlAliasesApi: string; + }>; readonly watcher: Record; readonly ccs: Record; readonly plugins: Record; @@ -230,6 +235,7 @@ readonly links: { datastreamsNamingScheme: string; upgradeElasticAgent: string; upgradeElasticAgent712lower: string; + learnMoreBlog: string; }>; readonly ecs: { readonly guide: string; diff --git a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md index f0fe058c403edf..04c2495cf3f1d6 100644 --- a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md +++ b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md @@ -17,5 +17,5 @@ export interface DocLinksStart | --- | --- | --- | | [DOC\_LINK\_VERSION](./kibana-plugin-core-public.doclinksstart.doc_link_version.md) | string | | | [ELASTIC\_WEBSITE\_URL](./kibana-plugin-core-public.doclinksstart.elastic_website_url.md) | string | | -| [links](./kibana-plugin-core-public.doclinksstart.links.md) | {
readonly settings: string;
readonly apm: {
readonly kibanaSettings: string;
readonly supportedServiceMaps: string;
readonly customLinks: string;
readonly droppedTransactionSpans: string;
readonly upgrading: string;
readonly metaData: string;
};
readonly canvas: {
readonly guide: string;
};
readonly dashboard: {
readonly guide: string;
readonly drilldowns: string;
readonly drilldownsTriggerPicker: string;
readonly urlDrilldownTemplateSyntax: string;
readonly urlDrilldownVariables: string;
};
readonly discover: Record<string, string>;
readonly filebeat: {
readonly base: string;
readonly installation: string;
readonly configuration: string;
readonly elasticsearchOutput: string;
readonly elasticsearchModule: string;
readonly startup: string;
readonly exportedFields: string;
readonly suricataModule: string;
readonly zeekModule: string;
};
readonly auditbeat: {
readonly base: string;
readonly auditdModule: string;
readonly systemModule: string;
};
readonly metricbeat: {
readonly base: string;
readonly configure: string;
readonly httpEndpoint: string;
readonly install: string;
readonly start: string;
};
readonly enterpriseSearch: {
readonly base: string;
readonly appSearchBase: string;
readonly workplaceSearchBase: string;
};
readonly heartbeat: {
readonly base: string;
};
readonly libbeat: {
readonly getStarted: string;
};
readonly logstash: {
readonly base: string;
};
readonly functionbeat: {
readonly base: string;
};
readonly winlogbeat: {
readonly base: string;
};
readonly aggs: {
readonly composite: string;
readonly composite_missing_bucket: string;
readonly date_histogram: string;
readonly date_range: string;
readonly date_format_pattern: string;
readonly filter: string;
readonly filters: string;
readonly geohash_grid: string;
readonly histogram: string;
readonly ip_range: string;
readonly range: string;
readonly significant_terms: string;
readonly terms: string;
readonly avg: string;
readonly avg_bucket: string;
readonly max_bucket: string;
readonly min_bucket: string;
readonly sum_bucket: string;
readonly cardinality: string;
readonly count: string;
readonly cumulative_sum: string;
readonly derivative: string;
readonly geo_bounds: string;
readonly geo_centroid: string;
readonly max: string;
readonly median: string;
readonly min: string;
readonly moving_avg: string;
readonly percentile_ranks: string;
readonly serial_diff: string;
readonly std_dev: string;
readonly sum: string;
readonly top_hits: string;
};
readonly runtimeFields: {
readonly overview: string;
readonly mapping: string;
};
readonly scriptedFields: {
readonly scriptFields: string;
readonly scriptAggs: string;
readonly painless: string;
readonly painlessApi: string;
readonly painlessLangSpec: string;
readonly painlessSyntax: string;
readonly painlessWalkthrough: string;
readonly luceneExpressions: string;
};
readonly search: {
readonly sessions: string;
readonly sessionLimits: string;
};
readonly indexPatterns: {
readonly introduction: string;
readonly fieldFormattersNumber: string;
readonly fieldFormattersString: string;
readonly runtimeFields: string;
};
readonly addData: string;
readonly kibana: string;
readonly upgradeAssistant: string;
readonly rollupJobs: string;
readonly elasticsearch: Record<string, string>;
readonly siem: {
readonly privileges: string;
readonly guide: string;
readonly gettingStarted: string;
readonly ml: string;
readonly ruleChangeLog: string;
readonly detectionsReq: string;
readonly networkMap: string;
};
readonly query: {
readonly eql: string;
readonly kueryQuerySyntax: string;
readonly luceneQuerySyntax: string;
readonly percolate: string;
readonly queryDsl: string;
readonly autocompleteChanges: string;
};
readonly date: {
readonly dateMath: string;
readonly dateMathIndexNames: string;
};
readonly management: Record<string, string>;
readonly ml: Record<string, string>;
readonly transforms: Record<string, string>;
readonly visualize: Record<string, string>;
readonly apis: Readonly<{
bulkIndexAlias: string;
byteSizeUnits: string;
createAutoFollowPattern: string;
createFollower: string;
createIndex: string;
createSnapshotLifecyclePolicy: string;
createRoleMapping: string;
createRoleMappingTemplates: string;
createRollupJobsRequest: string;
createApiKey: string;
createPipeline: string;
createTransformRequest: string;
cronExpressions: string;
executeWatchActionModes: string;
indexExists: string;
openIndex: string;
putComponentTemplate: string;
painlessExecute: string;
painlessExecuteAPIContexts: string;
putComponentTemplateMetadata: string;
putSnapshotLifecyclePolicy: string;
putIndexTemplateV1: string;
putWatch: string;
simulatePipeline: string;
timeUnits: string;
updateTransform: string;
}>;
readonly observability: Readonly<{
guide: string;
infrastructureThreshold: string;
logsThreshold: string;
metricsThreshold: string;
monitorStatus: string;
monitorUptime: string;
tlsCertificate: string;
uptimeDurationAnomaly: string;
}>;
readonly alerting: Record<string, string>;
readonly maps: Record<string, string>;
readonly monitoring: Record<string, string>;
readonly security: Readonly<{
apiKeyServiceSettings: string;
clusterPrivileges: string;
elasticsearchSettings: string;
elasticsearchEnableSecurity: string;
indicesPrivileges: string;
kibanaTLS: string;
kibanaPrivileges: string;
mappingRoles: string;
mappingRolesFieldRules: string;
runAsPrivilege: string;
}>;
readonly watcher: Record<string, string>;
readonly ccs: Record<string, string>;
readonly plugins: Record<string, string>;
readonly snapshotRestore: Record<string, string>;
readonly ingest: Record<string, string>;
readonly fleet: Readonly<{
guide: string;
fleetServer: string;
fleetServerAddFleetServer: string;
settings: string;
settingsFleetServerHostSettings: string;
troubleshooting: string;
elasticAgent: string;
datastreams: string;
datastreamsNamingScheme: string;
upgradeElasticAgent: string;
upgradeElasticAgent712lower: string;
}>;
readonly ecs: {
readonly guide: string;
};
readonly clients: {
readonly guide: string;
readonly goOverview: string;
readonly javaIndex: string;
readonly jsIntro: string;
readonly netGuide: string;
readonly perlGuide: string;
readonly phpGuide: string;
readonly pythonGuide: string;
readonly rubyOverview: string;
readonly rustGuide: string;
};
} | | +| [links](./kibana-plugin-core-public.doclinksstart.links.md) | {
readonly settings: string;
readonly apm: {
readonly kibanaSettings: string;
readonly supportedServiceMaps: string;
readonly customLinks: string;
readonly droppedTransactionSpans: string;
readonly upgrading: string;
readonly metaData: string;
};
readonly canvas: {
readonly guide: string;
};
readonly dashboard: {
readonly guide: string;
readonly drilldowns: string;
readonly drilldownsTriggerPicker: string;
readonly urlDrilldownTemplateSyntax: string;
readonly urlDrilldownVariables: string;
};
readonly discover: Record<string, string>;
readonly filebeat: {
readonly base: string;
readonly installation: string;
readonly configuration: string;
readonly elasticsearchOutput: string;
readonly elasticsearchModule: string;
readonly startup: string;
readonly exportedFields: string;
readonly suricataModule: string;
readonly zeekModule: string;
};
readonly auditbeat: {
readonly base: string;
readonly auditdModule: string;
readonly systemModule: string;
};
readonly metricbeat: {
readonly base: string;
readonly configure: string;
readonly httpEndpoint: string;
readonly install: string;
readonly start: string;
};
readonly enterpriseSearch: {
readonly base: string;
readonly appSearchBase: string;
readonly workplaceSearchBase: string;
};
readonly heartbeat: {
readonly base: string;
};
readonly libbeat: {
readonly getStarted: string;
};
readonly logstash: {
readonly base: string;
};
readonly functionbeat: {
readonly base: string;
};
readonly winlogbeat: {
readonly base: string;
};
readonly aggs: {
readonly composite: string;
readonly composite_missing_bucket: string;
readonly date_histogram: string;
readonly date_range: string;
readonly date_format_pattern: string;
readonly filter: string;
readonly filters: string;
readonly geohash_grid: string;
readonly histogram: string;
readonly ip_range: string;
readonly range: string;
readonly significant_terms: string;
readonly terms: string;
readonly avg: string;
readonly avg_bucket: string;
readonly max_bucket: string;
readonly min_bucket: string;
readonly sum_bucket: string;
readonly cardinality: string;
readonly count: string;
readonly cumulative_sum: string;
readonly derivative: string;
readonly geo_bounds: string;
readonly geo_centroid: string;
readonly max: string;
readonly median: string;
readonly min: string;
readonly moving_avg: string;
readonly percentile_ranks: string;
readonly serial_diff: string;
readonly std_dev: string;
readonly sum: string;
readonly top_hits: string;
};
readonly runtimeFields: {
readonly overview: string;
readonly mapping: string;
};
readonly scriptedFields: {
readonly scriptFields: string;
readonly scriptAggs: string;
readonly painless: string;
readonly painlessApi: string;
readonly painlessLangSpec: string;
readonly painlessSyntax: string;
readonly painlessWalkthrough: string;
readonly luceneExpressions: string;
};
readonly search: {
readonly sessions: string;
readonly sessionLimits: string;
};
readonly indexPatterns: {
readonly introduction: string;
readonly fieldFormattersNumber: string;
readonly fieldFormattersString: string;
readonly runtimeFields: string;
};
readonly addData: string;
readonly kibana: string;
readonly upgradeAssistant: string;
readonly rollupJobs: string;
readonly elasticsearch: Record<string, string>;
readonly siem: {
readonly privileges: string;
readonly guide: string;
readonly gettingStarted: string;
readonly ml: string;
readonly ruleChangeLog: string;
readonly detectionsReq: string;
readonly networkMap: string;
};
readonly query: {
readonly eql: string;
readonly kueryQuerySyntax: string;
readonly luceneQuerySyntax: string;
readonly percolate: string;
readonly queryDsl: string;
readonly autocompleteChanges: string;
};
readonly date: {
readonly dateMath: string;
readonly dateMathIndexNames: string;
};
readonly management: Record<string, string>;
readonly ml: Record<string, string>;
readonly transforms: Record<string, string>;
readonly visualize: Record<string, string>;
readonly apis: Readonly<{
bulkIndexAlias: string;
byteSizeUnits: string;
createAutoFollowPattern: string;
createFollower: string;
createIndex: string;
createSnapshotLifecyclePolicy: string;
createRoleMapping: string;
createRoleMappingTemplates: string;
createRollupJobsRequest: string;
createApiKey: string;
createPipeline: string;
createTransformRequest: string;
cronExpressions: string;
executeWatchActionModes: string;
indexExists: string;
openIndex: string;
putComponentTemplate: string;
painlessExecute: string;
painlessExecuteAPIContexts: string;
putComponentTemplateMetadata: string;
putSnapshotLifecyclePolicy: string;
putIndexTemplateV1: string;
putWatch: string;
simulatePipeline: string;
timeUnits: string;
updateTransform: string;
}>;
readonly observability: Readonly<{
guide: string;
infrastructureThreshold: string;
logsThreshold: string;
metricsThreshold: string;
monitorStatus: string;
monitorUptime: string;
tlsCertificate: string;
uptimeDurationAnomaly: string;
}>;
readonly alerting: Record<string, string>;
readonly maps: Record<string, string>;
readonly monitoring: Record<string, string>;
readonly security: Readonly<{
apiKeyServiceSettings: string;
clusterPrivileges: string;
elasticsearchSettings: string;
elasticsearchEnableSecurity: string;
indicesPrivileges: string;
kibanaTLS: string;
kibanaPrivileges: string;
mappingRoles: string;
mappingRolesFieldRules: string;
runAsPrivilege: string;
}>;
readonly spaces: Readonly<{
kibanaLegacyUrlAliases: string;
kibanaDisableLegacyUrlAliasesApi: string;
}>;
readonly watcher: Record<string, string>;
readonly ccs: Record<string, string>;
readonly plugins: Record<string, string>;
readonly snapshotRestore: Record<string, string>;
readonly ingest: Record<string, string>;
readonly fleet: Readonly<{
guide: string;
fleetServer: string;
fleetServerAddFleetServer: string;
settings: string;
settingsFleetServerHostSettings: string;
troubleshooting: string;
elasticAgent: string;
datastreams: string;
datastreamsNamingScheme: string;
upgradeElasticAgent: string;
upgradeElasticAgent712lower: string;
}>;
readonly ecs: {
readonly guide: string;
};
readonly clients: {
readonly guide: string;
readonly goOverview: string;
readonly javaIndex: string;
readonly jsIntro: string;
readonly netGuide: string;
readonly perlGuide: string;
readonly phpGuide: string;
readonly pythonGuide: string;
readonly rubyOverview: string;
readonly rustGuide: string;
};
} | | diff --git a/docs/development/core/public/kibana-plugin-core-public.httpsetup.fetch.md b/docs/development/core/public/kibana-plugin-core-public.httpsetup.fetch.md index 6bdbaf4ee2f36d..ad232598b71cac 100644 --- a/docs/development/core/public/kibana-plugin-core-public.httpsetup.fetch.md +++ b/docs/development/core/public/kibana-plugin-core-public.httpsetup.fetch.md @@ -4,7 +4,7 @@ ## HttpSetup.fetch property -Makes an HTTP request. Defaults to a GET request unless overriden. See [HttpHandler](./kibana-plugin-core-public.httphandler.md) for options. +Makes an HTTP request. Defaults to a GET request unless overridden. See [HttpHandler](./kibana-plugin-core-public.httphandler.md) for options. Signature: diff --git a/docs/development/core/public/kibana-plugin-core-public.httpsetup.md b/docs/development/core/public/kibana-plugin-core-public.httpsetup.md index b8a99cbb623537..a921110018c700 100644 --- a/docs/development/core/public/kibana-plugin-core-public.httpsetup.md +++ b/docs/development/core/public/kibana-plugin-core-public.httpsetup.md @@ -19,7 +19,7 @@ export interface HttpSetup | [basePath](./kibana-plugin-core-public.httpsetup.basepath.md) | IBasePath | APIs for manipulating the basePath on URL segments. See [IBasePath](./kibana-plugin-core-public.ibasepath.md) | | [delete](./kibana-plugin-core-public.httpsetup.delete.md) | HttpHandler | Makes an HTTP request with the DELETE method. See [HttpHandler](./kibana-plugin-core-public.httphandler.md) for options. | | [externalUrl](./kibana-plugin-core-public.httpsetup.externalurl.md) | IExternalUrl | | -| [fetch](./kibana-plugin-core-public.httpsetup.fetch.md) | HttpHandler | Makes an HTTP request. Defaults to a GET request unless overriden. See [HttpHandler](./kibana-plugin-core-public.httphandler.md) for options. | +| [fetch](./kibana-plugin-core-public.httpsetup.fetch.md) | HttpHandler | Makes an HTTP request. Defaults to a GET request unless overridden. See [HttpHandler](./kibana-plugin-core-public.httphandler.md) for options. | | [get](./kibana-plugin-core-public.httpsetup.get.md) | HttpHandler | Makes an HTTP request with the GET method. See [HttpHandler](./kibana-plugin-core-public.httphandler.md) for options. | | [head](./kibana-plugin-core-public.httpsetup.head.md) | HttpHandler | Makes an HTTP request with the HEAD method. See [HttpHandler](./kibana-plugin-core-public.httphandler.md) for options. | | [options](./kibana-plugin-core-public.httpsetup.options.md) | HttpHandler | Makes an HTTP request with the OPTIONS method. See [HttpHandler](./kibana-plugin-core-public.httphandler.md) for options. | diff --git a/docs/development/core/server/kibana-plugin-core-server.md b/docs/development/core/server/kibana-plugin-core-server.md index 89203cb94d573b..76b48358363e08 100644 --- a/docs/development/core/server/kibana-plugin-core-server.md +++ b/docs/development/core/server/kibana-plugin-core-server.md @@ -303,7 +303,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [SavedObjectAttributeSingle](./kibana-plugin-core-server.savedobjectattributesingle.md) | Don't use this type, it's simply a helper type for [SavedObjectAttribute](./kibana-plugin-core-server.savedobjectattribute.md) | | [SavedObjectMigrationFn](./kibana-plugin-core-server.savedobjectmigrationfn.md) | A migration function for a [saved object type](./kibana-plugin-core-server.savedobjectstype.md) used to migrate it to a given version | | [SavedObjectSanitizedDoc](./kibana-plugin-core-server.savedobjectsanitizeddoc.md) | Describes Saved Object documents that have passed through the migration framework and are guaranteed to have a references root property. | -| [SavedObjectsClientContract](./kibana-plugin-core-server.savedobjectsclientcontract.md) | Saved Objects is Kibana's data persisentence mechanism allowing plugins to use Elasticsearch for storing plugin state.\#\# SavedObjectsClient errorsSince the SavedObjectsClient has its hands in everything we are a little paranoid about the way we present errors back to to application code. Ideally, all errors will be either:1. Caused by bad implementation (ie. undefined is not a function) and as such unpredictable 2. An error that has been classified and decorated appropriately by the decorators in [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md)Type 1 errors are inevitable, but since all expected/handle-able errors should be Type 2 the isXYZError() helpers exposed at SavedObjectsErrorHelpers should be used to understand and manage error responses from the SavedObjectsClient.Type 2 errors are decorated versions of the source error, so if the elasticsearch client threw an error it will be decorated based on its type. That means that rather than looking for error.body.error.type or doing substring checks on error.body.error.reason, just use the helpers to understand the meaning of the error:\`\`\`js if (SavedObjectsErrorHelpers.isNotFoundError(error)) { // handle 404 }if (SavedObjectsErrorHelpers.isNotAuthorizedError(error)) { // 401 handling should be automatic, but in case you wanted to know }// always rethrow the error unless you handle it throw error; \`\`\`\#\#\# 404s from missing indexFrom the perspective of application code and APIs the SavedObjectsClient is a black box that persists objects. One of the internal details that users have no control over is that we use an elasticsearch index for persistance and that index might be missing.At the time of writing we are in the process of transitioning away from the operating assumption that the SavedObjects index is always available. Part of this transition is handling errors resulting from an index missing. These used to trigger a 500 error in most cases, and in others cause 404s with different error messages.From my (Spencer) perspective, a 404 from the SavedObjectsApi is a 404; The object the request/call was targeting could not be found. This is why \#14141 takes special care to ensure that 404 errors are generic and don't distinguish between index missing or document missing.See [SavedObjectsClient](./kibana-plugin-core-server.savedobjectsclient.md) See [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) | +| [SavedObjectsClientContract](./kibana-plugin-core-server.savedobjectsclientcontract.md) | Saved Objects is Kibana's data persisentence mechanism allowing plugins to use Elasticsearch for storing plugin state.\#\# SavedObjectsClient errorsSince the SavedObjectsClient has its hands in everything we are a little paranoid about the way we present errors back to to application code. Ideally, all errors will be either:1. Caused by bad implementation (ie. undefined is not a function) and as such unpredictable 2. An error that has been classified and decorated appropriately by the decorators in [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md)Type 1 errors are inevitable, but since all expected/handle-able errors should be Type 2 the isXYZError() helpers exposed at SavedObjectsErrorHelpers should be used to understand and manage error responses from the SavedObjectsClient.Type 2 errors are decorated versions of the source error, so if the elasticsearch client threw an error it will be decorated based on its type. That means that rather than looking for error.body.error.type or doing substring checks on error.body.error.reason, just use the helpers to understand the meaning of the error:\`\`\`js if (SavedObjectsErrorHelpers.isNotFoundError(error)) { // handle 404 }if (SavedObjectsErrorHelpers.isNotAuthorizedError(error)) { // 401 handling should be automatic, but in case you wanted to know }// always rethrow the error unless you handle it throw error; \`\`\`\#\#\# 404s from missing indexFrom the perspective of application code and APIs the SavedObjectsClient is a black box that persists objects. One of the internal details that users have no control over is that we use an elasticsearch index for persistence and that index might be missing.At the time of writing we are in the process of transitioning away from the operating assumption that the SavedObjects index is always available. Part of this transition is handling errors resulting from an index missing. These used to trigger a 500 error in most cases, and in others cause 404s with different error messages.From my (Spencer) perspective, a 404 from the SavedObjectsApi is a 404; The object the request/call was targeting could not be found. This is why \#14141 takes special care to ensure that 404 errors are generic and don't distinguish between index missing or document missing.See [SavedObjectsClient](./kibana-plugin-core-server.savedobjectsclient.md) See [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) | | [SavedObjectsClientFactory](./kibana-plugin-core-server.savedobjectsclientfactory.md) | Describes the factory used to create instances of the Saved Objects Client. | | [SavedObjectsClientFactoryProvider](./kibana-plugin-core-server.savedobjectsclientfactoryprovider.md) | Provider to invoke to retrieve a [SavedObjectsClientFactory](./kibana-plugin-core-server.savedobjectsclientfactory.md). | | [SavedObjectsClientWrapperFactory](./kibana-plugin-core-server.savedobjectsclientwrapperfactory.md) | Describes the factory used to create instances of Saved Objects Client Wrappers. | diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsclientcontract.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsclientcontract.md index 610356a733126e..f4e7895a3f3ebc 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsclientcontract.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsclientcontract.md @@ -24,7 +24,7 @@ if (SavedObjectsErrorHelpers.isNotAuthorizedError(error)) { // 401 handling shou \#\#\# 404s from missing index -From the perspective of application code and APIs the SavedObjectsClient is a black box that persists objects. One of the internal details that users have no control over is that we use an elasticsearch index for persistance and that index might be missing. +From the perspective of application code and APIs the SavedObjectsClient is a black box that persists objects. One of the internal details that users have no control over is that we use an elasticsearch index for persistence and that index might be missing. At the time of writing we are in the process of transitioning away from the operating assumption that the SavedObjects index is always available. Part of this transition is handling errors resulting from an index missing. These used to trigger a 500 error in most cases, and in others cause 404s with different error messages. diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsexporterror.invalidtransformerror.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsexporterror.invalidtransformerror.md index 5a390bd4504217..103d1ff8a912ba 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsexporterror.invalidtransformerror.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsexporterror.invalidtransformerror.md @@ -4,7 +4,7 @@ ## SavedObjectsExportError.invalidTransformError() method -Error returned when a [export tranform](./kibana-plugin-core-server.savedobjectsexporttransform.md) performed an invalid operation during the transform, such as removing objects from the export, or changing an object's type or id. +Error returned when a [export transform](./kibana-plugin-core-server.savedobjectsexporttransform.md) performed an invalid operation during the transform, such as removing objects from the export, or changing an object's type or id. Signature: diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsexporterror.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsexporterror.md index 7d5c6e5d89a5b8..2a503f9377daca 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsexporterror.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsexporterror.md @@ -29,7 +29,7 @@ export declare class SavedObjectsExportError extends Error | Method | Modifiers | Description | | --- | --- | --- | | [exportSizeExceeded(limit)](./kibana-plugin-core-server.savedobjectsexporterror.exportsizeexceeded.md) | static | | -| [invalidTransformError(objectKeys)](./kibana-plugin-core-server.savedobjectsexporterror.invalidtransformerror.md) | static | Error returned when a [export tranform](./kibana-plugin-core-server.savedobjectsexporttransform.md) performed an invalid operation during the transform, such as removing objects from the export, or changing an object's type or id. | +| [invalidTransformError(objectKeys)](./kibana-plugin-core-server.savedobjectsexporterror.invalidtransformerror.md) | static | Error returned when a [export transform](./kibana-plugin-core-server.savedobjectsexporttransform.md) performed an invalid operation during the transform, such as removing objects from the export, or changing an object's type or id. | | [objectFetchError(objects)](./kibana-plugin-core-server.savedobjectsexporterror.objectfetcherror.md) | static | | -| [objectTransformError(objects, cause)](./kibana-plugin-core-server.savedobjectsexporterror.objecttransformerror.md) | static | Error returned when a [export tranform](./kibana-plugin-core-server.savedobjectsexporttransform.md) threw an error | +| [objectTransformError(objects, cause)](./kibana-plugin-core-server.savedobjectsexporterror.objecttransformerror.md) | static | Error returned when a [export transform](./kibana-plugin-core-server.savedobjectsexporttransform.md) threw an error | diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsexporterror.objecttransformerror.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsexporterror.objecttransformerror.md index 4463e9ff06da02..393cf20dbae16b 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsexporterror.objecttransformerror.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsexporterror.objecttransformerror.md @@ -4,7 +4,7 @@ ## SavedObjectsExportError.objectTransformError() method -Error returned when a [export tranform](./kibana-plugin-core-server.savedobjectsexporttransform.md) threw an error +Error returned when a [export transform](./kibana-plugin-core-server.savedobjectsexporttransform.md) threw an error Signature: diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsimporter.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsimporter.md index ad07c23ae70343..cd5c71077e6660 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsimporter.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsimporter.md @@ -28,5 +28,5 @@ export declare class SavedObjectsImporter | Method | Modifiers | Description | | --- | --- | --- | | [import({ readStream, createNewCopies, namespace, overwrite, })](./kibana-plugin-core-server.savedobjectsimporter.import.md) | | Import saved objects from given stream. See the [options](./kibana-plugin-core-server.savedobjectsimportoptions.md) for more detailed information. | -| [resolveImportErrors({ readStream, createNewCopies, namespace, retries, })](./kibana-plugin-core-server.savedobjectsimporter.resolveimporterrors.md) | | Resolve and return saved object import errors. See the [options](./kibana-plugin-core-server.savedobjectsresolveimporterrorsoptions.md) for more detailed informations. | +| [resolveImportErrors({ readStream, createNewCopies, namespace, retries, })](./kibana-plugin-core-server.savedobjectsimporter.resolveimporterrors.md) | | Resolve and return saved object import errors. See the [options](./kibana-plugin-core-server.savedobjectsresolveimporterrorsoptions.md) for more detailed information. | diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsimporter.resolveimporterrors.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsimporter.resolveimporterrors.md index c4ea529d30eff7..9418b581ad5b20 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsimporter.resolveimporterrors.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsimporter.resolveimporterrors.md @@ -4,7 +4,7 @@ ## SavedObjectsImporter.resolveImportErrors() method -Resolve and return saved object import errors. See the [options](./kibana-plugin-core-server.savedobjectsresolveimporterrorsoptions.md) for more detailed informations. +Resolve and return saved object import errors. See the [options](./kibana-plugin-core-server.savedobjectsresolveimporterrorsoptions.md) for more detailed information. Signature: diff --git a/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.derivedstatus_.md b/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.derivedstatus_.md index 6c65e44270a063..96784359457fbf 100644 --- a/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.derivedstatus_.md +++ b/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.derivedstatus_.md @@ -16,5 +16,5 @@ derivedStatus$: Observable; By default, plugins inherit this derived status from their dependencies. Calling overrides this default status. -This may emit multliple times for a single status change event as propagates through the dependency tree +This may emit multiple times for a single status change event as propagates through the dependency tree diff --git a/docs/management/field-formatters/url-formatter.asciidoc b/docs/management/field-formatters/url-formatter.asciidoc index 8b0e43c9f24968..626dcd37c86eaa 100644 --- a/docs/management/field-formatters/url-formatter.asciidoc +++ b/docs/management/field-formatters/url-formatter.asciidoc @@ -1,7 +1,7 @@ You can specify the following types to the `Url` field formatter: * *Link* — Converts the contents of the field into an URL. You can specify the width and height of the image, while keeping the aspect ratio. -When the image is smaller than the specified paramters, the image is unable to upscale. +When the image is smaller than the specified parameters, the image is unable to upscale. * *Image* — Specifies the image directory. * *Audio* — Specify the audio directory. diff --git a/docs/maps/asset-tracking-tutorial.asciidoc b/docs/maps/asset-tracking-tutorial.asciidoc index 822510e882c128..4ba045681e1486 100644 --- a/docs/maps/asset-tracking-tutorial.asciidoc +++ b/docs/maps/asset-tracking-tutorial.asciidoc @@ -249,7 +249,7 @@ image::maps/images/asset-tracking-tutorial/top_hits_layer_style.png[] . Click *Save & close*. . Open the <>, and set *Refresh every* to 10 seconds, and click *Start*. -Your map should automatically refresh every 10 seconds to show the lastest bus positions and tracks. +Your map should automatically refresh every 10 seconds to show the latest bus positions and tracks. [role="screenshot"] image::maps/images/asset-tracking-tutorial/tracks_and_top_hits.png[] diff --git a/docs/maps/maps-getting-started.asciidoc b/docs/maps/maps-getting-started.asciidoc index 64ab6fca0714ef..014be570253bb7 100644 --- a/docs/maps/maps-getting-started.asciidoc +++ b/docs/maps/maps-getting-started.asciidoc @@ -136,7 +136,7 @@ grids with less bytes transferred. ** **Visibility** to the range [0, 9] ** **Opacity** to 100% . In **Metrics**: -** Set **Agregation** to **Count**. +** Set **Aggregation** to **Count**. ** Click **Add metric**. ** Set **Aggregation** to **Sum** with **Field** set to **bytes**. . In **Layer style**, change **Symbol size**: diff --git a/docs/maps/reverse-geocoding-tutorial.asciidoc b/docs/maps/reverse-geocoding-tutorial.asciidoc index 2dcbcdfa8a1fb0..0c942f120a4da6 100644 --- a/docs/maps/reverse-geocoding-tutorial.asciidoc +++ b/docs/maps/reverse-geocoding-tutorial.asciidoc @@ -4,7 +4,7 @@ *Maps* comes with https://maps.elastic.co/#file[predefined regions] that allow you to quickly visualize regions by metrics. *Maps* also offers the ability to map your own regions. You can use any region data you'd like, as long as your source data contains an identifier for the corresponding region. -But how can you map regions when your source data does not contain a region identifier? This is where reverse geocoding comes in. Reverse geocoding is the process of assigning a region identifer to a feature based on its location. +But how can you map regions when your source data does not contain a region identifier? This is where reverse geocoding comes in. Reverse geocoding is the process of assigning a region identifier to a feature based on its location. In this tutorial, you’ll use reverse geocoding to visualize United States Census Bureau Combined Statistical Area (CSA) regions by web traffic. diff --git a/docs/maps/search.asciidoc b/docs/maps/search.asciidoc index af6939eb8ae114..08624e4ddff57f 100644 --- a/docs/maps/search.asciidoc +++ b/docs/maps/search.asciidoc @@ -84,7 +84,7 @@ Create filters from your map to focus in on just the data you want. *Maps* provi ==== Filter dashboard by map extent A map extent shows uniform data across all panels. -As you pan and zoom your map, all panels will update to only include data that is visable in your map. +As you pan and zoom your map, all panels will update to only include data that is visible in your map. To enable filtering your dashboard by map extent: diff --git a/docs/maps/vector-style.asciidoc b/docs/maps/vector-style.asciidoc index eff608e354a995..bb25b276b2deef 100644 --- a/docs/maps/vector-style.asciidoc +++ b/docs/maps/vector-style.asciidoc @@ -10,7 +10,7 @@ For each property, you can specify whether to use a constant or data driven valu [[maps-vector-style-static]] ==== Static styling -Use static styling to specificy a constant value for a style property. +Use static styling to specify a constant value for a style property. This image shows an example of static styling using the <> data set. The *kibana_sample_data_logs* layer uses static styling for all properties. diff --git a/docs/settings/alert-action-settings.asciidoc b/docs/settings/alert-action-settings.asciidoc index 3a94e652d2ea00..599e8c54643ce6 100644 --- a/docs/settings/alert-action-settings.asciidoc +++ b/docs/settings/alert-action-settings.asciidoc @@ -46,10 +46,13 @@ entry. + In the following example, two custom host settings are defined. The first provides a custom host setting for mail server -`mail.example.com` using port 465 that supplies server certificate authorization +`mail.example.com` using port 465 that supplies server certificate authentication data from both a file and inline, and requires TLS for the connection. The second provides a custom host setting for https server -`webhook.example.com` which turns off server certificate authorization. +`webhook.example.com` which turns off server certificate authentication, +that will allow Kibana to connect to the server if it's using a self-signed +certificate. The individual properties that can be used in the settings are +documented below. + [source,yaml] -- @@ -66,11 +69,16 @@ xpack.actions.customHostSettings: requireTLS: true - url: https://webhook.example.com ssl: - // legacy - rejectUnauthorized: false verificationMode: 'none' -- +The settings in `xpack.actions.customHostSettings` can be used to override the +global option `xpack.actions.ssl.verificationMode` and provide customized TLS +settings on a per-server basis. Set `xpack.actions.ssl.verificationMode` to the +value to be used by default for all servers, then add an entry in +`xpack.actions.customHostSettings` for every server that requires customized +settings. + `xpack.actions.customHostSettings[n].url` {ess-icon}:: A URL associated with this custom host setting. Should be in the form of `protocol://hostname:port`, where `protocol` is `https` or `smtp`. If the @@ -91,10 +99,12 @@ values. `xpack.actions.customHostSettings[n].smtp.ignoreTLS` {ess-icon}:: A boolean value indicating that TLS must not be used for this connection. The options `smtp.ignoreTLS` and `smtp.requireTLS` can not both be set to true. +Default: `false`. `xpack.actions.customHostSettings[n].smtp.requireTLS` {ess-icon}:: A boolean value indicating that TLS must be used for this connection. The options `smtp.ignoreTLS` and `smtp.requireTLS` can not both be set to true. +Default: `false`. `xpack.actions.customHostSettings[n].ssl.rejectUnauthorized`:: Deprecated. Use <> instead. A boolean value indicating whether to bypass server certificate validation. @@ -141,8 +151,8 @@ Specifies HTTP headers for the proxy, if using a proxy for actions. Default: {}. `xpack.actions.proxyRejectUnauthorizedCertificates` {ess-icon}:: Deprecated. Use <> instead. Set to `false` to bypass certificate validation for the proxy, if using a proxy for actions. Default: `true`. -[[action-config-proxy-verification-mode]]`xpack.actions[n].ssl.proxyVerificationMode` {ess-icon}:: -Controls the verification for the proxy server certificate that {hosted-ems} receives when making an outbound SSL/TLS connection to the proxy server. Valid values are `full`, `certificate`, and `none`. +[[action-config-proxy-verification-mode]]`xpack.actions.ssl.proxyVerificationMode` {ess-icon}:: +Controls the verification for the proxy server certificate that Kibana receives when making an outbound SSL/TLS connection to the proxy server. Valid values are `full`, `certificate`, and `none`. Use `full` to perform hostname verification, `certificate` to skip hostname verification, and `none` to skip verification. Default: `full`. <>. `xpack.actions.rejectUnauthorized` {ess-icon}:: @@ -151,12 +161,12 @@ Deprecated. Use <>. + -As an alternative to setting `xpack.actions.ssl.verificationMode`, you can use the setting -`xpack.actions.customHostSettings` to set SSL options for specific servers. +This setting can be overridden for specific URLs by using the setting +`xpack.actions.customHostSettings[n].ssl.verificationMode` (described above) to a different value. `xpack.actions.maxResponseContentLength` {ess-icon}:: Specifies the max number of bytes of the http response for requests to external resources. Default: 1000000 (1MB). diff --git a/docs/settings/fleet-settings.asciidoc b/docs/settings/fleet-settings.asciidoc index bf5c84324b0b97..f6f5b4a79fb6d1 100644 --- a/docs/settings/fleet-settings.asciidoc +++ b/docs/settings/fleet-settings.asciidoc @@ -101,7 +101,7 @@ Optional properties are: prevent that specific `var` from being edited by the user. | `xpack.fleet.outputs` - | List of ouputs that are configured when the {fleet} app starts. + | List of outputs that are configured when the {fleet} app starts. Required properties are: `id`:: Unique ID for this output. The ID should be a string. diff --git a/docs/settings/task-manager-settings.asciidoc b/docs/settings/task-manager-settings.asciidoc index fa89b7780e475f..ef45c262f897b7 100644 --- a/docs/settings/task-manager-settings.asciidoc +++ b/docs/settings/task-manager-settings.asciidoc @@ -57,6 +57,6 @@ Settings that configure the <> endpoint. |=== | `xpack.task_manager.` `monitored_task_execution_thresholds` - | Configures the threshold of failed task executions at which point the `warn` or `error` health status is set under each task type execution status (under `stats.runtime.value.excution.result_frequency_percent_as_number[${task type}].status`). This setting allows configuration of both the default level and a custom task type specific level. By default, this setting is configured to mark the health of every task type as `warning` when it exceeds 80% failed executions, and as `error` at 90%. Custom configurations allow you to reduce this threshold to catch failures sooner for task types that you might consider critical, such as alerting tasks. This value can be set to any number between 0 to 100, and a threshold is hit when the value *exceeds* this number. This means that you can avoid setting the status to `error` by setting the threshold at 100, or hit `error` the moment any task fails by setting the threshold to 0 (as it will exceed 0 once a single failure occurs). + | Configures the threshold of failed task executions at which point the `warn` or `error` health status is set under each task type execution status (under `stats.runtime.value.execution.result_frequency_percent_as_number[${task type}].status`). This setting allows configuration of both the default level and a custom task type specific level. By default, this setting is configured to mark the health of every task type as `warning` when it exceeds 80% failed executions, and as `error` at 90%. Custom configurations allow you to reduce this threshold to catch failures sooner for task types that you might consider critical, such as alerting tasks. This value can be set to any number between 0 to 100, and a threshold is hit when the value *exceeds* this number. This means that you can avoid setting the status to `error` by setting the threshold at 100, or hit `error` the moment any task fails by setting the threshold to 0 (as it will exceed 0 once a single failure occurs). |=== diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 7a85411065db66..9c3d4fc29f137d 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -428,14 +428,14 @@ in a manner that is inconsistent with `/proc/self/cgroup`. |[[savedObjects-maxImportExportSize]] `savedObjects.maxImportExportSize:` | The maximum count of saved objects that can be imported or exported. -This setting exists to prevent the {kib} server from runnning out of memory when handling +This setting exists to prevent the {kib} server from running out of memory when handling large numbers of saved objects. It is recommended to only raise this setting if you are confident your server can hold this many objects in memory. *Default: `10000`* |[[savedObjects-maxImportPayloadBytes]] `savedObjects.maxImportPayloadBytes:` | The maximum byte size of a saved objects import that the {kib} server will accept. -This setting exists to prevent the {kib} server from runnning out of memory when handling +This setting exists to prevent the {kib} server from running out of memory when handling a large import payload. Note that this setting overrides the more general <> for saved object imports only. *Default: `26214400`* diff --git a/docs/spaces/index.asciidoc b/docs/spaces/index.asciidoc index 6722503eb03232..28d29e4822f83f 100644 --- a/docs/spaces/index.asciidoc +++ b/docs/spaces/index.asciidoc @@ -43,7 +43,7 @@ on the name of your space, but you can customize the identifier to your liking. You cannot change the space identifier once you create the space. {kib} also has an <> -if you prefer to create spaces programatically. +if you prefer to create spaces programmatically. [role="screenshot"] image::images/edit-space.png["Space management"] @@ -70,7 +70,7 @@ to specific features on a per-user basis, you must configure <>. [role="screenshot"] -image::images/edit-space-feature-visibility.png["Controlling features visiblity"] +image::images/edit-space-feature-visibility.png["Controlling features visibility"] [float] [[spaces-control-user-access]] @@ -84,7 +84,7 @@ while analysts or executives might have read-only privileges for *Dashboard* and Refer to <> for details. [role="screenshot"] -image::images/spaces-roles.png["Controlling features visiblity"] +image::images/spaces-roles.png["Controlling features visibility"] [float] [[spaces-moving-objects]] diff --git a/docs/user/alerting/rule-types.asciidoc b/docs/user/alerting/rule-types.asciidoc index f7f57d2f845a09..4c1d3b94bdee66 100644 --- a/docs/user/alerting/rule-types.asciidoc +++ b/docs/user/alerting/rule-types.asciidoc @@ -41,7 +41,7 @@ Domain rules are registered by *Observability*, *Security*, <> and < | Detect complex conditions in the *Logs*, *Metrics*, and *Uptime* apps. | {security-guide}/prebuilt-rules.html[Security rules] -| Detect suspicous source events with pre-built or custom rules and create alerts when a rule’s conditions are met. +| Detect suspicious source events with pre-built or custom rules and create alerts when a rule’s conditions are met. | <> | Run an {es} query to determine if any documents are currently contained in any boundaries from a specified boundary index and generate alerts when a rule's conditions are met. diff --git a/docs/user/alerting/rule-types/es-query.asciidoc b/docs/user/alerting/rule-types/es-query.asciidoc index 65d39ba170c3c9..86367a6a2e2c09 100644 --- a/docs/user/alerting/rule-types/es-query.asciidoc +++ b/docs/user/alerting/rule-types/es-query.asciidoc @@ -19,7 +19,7 @@ image::user/alerting/images/rule-types-es-query-conditions.png[Five clauses defi Index:: This clause requires an *index or index pattern* and a *time field* that will be used for the *time window*. Size:: This clause specifies the number of documents to pass to the configured actions when the the threshold condition is met. -{es} query:: This clause specifies the ES DSL query to execute. The number of documents that match this query will be evaulated against the threshold +{es} query:: This clause specifies the ES DSL query to execute. The number of documents that match this query will be evaluated against the threshold condition. Aggregations are not supported at this time. Threshold:: This clause defines a threshold value and a comparison operator (`is above`, `is above or equals`, `is below`, `is below or equals`, or `is between`). The number of documents that match the specified query is compared to this threshold. Time window:: This clause determines how far back to search for documents, using the *time field* set in the *index* clause. Generally this value should be set to a value higher than the *check every* value in the <>, to avoid gaps in detection. diff --git a/docs/user/dashboard/tsvb.asciidoc b/docs/user/dashboard/tsvb.asciidoc index 0537677ee3ad9f..9fe6af2d3da6df 100644 --- a/docs/user/dashboard/tsvb.asciidoc +++ b/docs/user/dashboard/tsvb.asciidoc @@ -208,7 +208,7 @@ For example `dashboards#/view/f193ca90-c9f4-11eb-b038-dd3270053a27`. . Click *Save and return*. -. In the toolbar, cick *Save as*, then make sure *Store time with dashboard* is deselected. +. In the toolbar, click *Save as*, then make sure *Store time with dashboard* is deselected. ==== [discrete] diff --git a/docs/user/production-considerations/alerting-production-considerations.asciidoc b/docs/user/production-considerations/alerting-production-considerations.asciidoc index cd8a60a1d5fe3e..42f9a17cc6f888 100644 --- a/docs/user/production-considerations/alerting-production-considerations.asciidoc +++ b/docs/user/production-considerations/alerting-production-considerations.asciidoc @@ -52,7 +52,7 @@ Predicting the buffer required to account for actions depends heavily on the rul [float] [[event-log-ilm]] -=== Event log index lifecycle managment +=== Event log index lifecycle management experimental[] diff --git a/docs/user/production-considerations/task-manager-health-monitoring.asciidoc b/docs/user/production-considerations/task-manager-health-monitoring.asciidoc index b07a01906b8953..6232f20d289721 100644 --- a/docs/user/production-considerations/task-manager-health-monitoring.asciidoc +++ b/docs/user/production-considerations/task-manager-health-monitoring.asciidoc @@ -109,7 +109,7 @@ a| Workload a| Runtime -| This section tracks excution performance of Task Manager, tracking task _drift_, worker _load_, and execution stats broken down by type, including duration and execution results. +| This section tracks execution performance of Task Manager, tracking task _drift_, worker _load_, and execution stats broken down by type, including duration and execution results. a| Capacity Estimation diff --git a/docs/user/production-considerations/task-manager-production-considerations.asciidoc b/docs/user/production-considerations/task-manager-production-considerations.asciidoc index 17eae59ff2f9c2..0de32bf00948bc 100644 --- a/docs/user/production-considerations/task-manager-production-considerations.asciidoc +++ b/docs/user/production-considerations/task-manager-production-considerations.asciidoc @@ -68,7 +68,7 @@ This means that you can expect a single {kib} instance to support up to 200 _tas In practice, a {kib} instance will only achieve the upper bound of `200/tpm` if the duration of task execution is below the polling rate of 3 seconds. For the most part, the duration of tasks is below that threshold, but it can vary greatly as {es} and {kib} usage grow and task complexity increases (such as alerts executing heavy queries across large datasets). -By <>, you can estimate the number of {kib} instances required to reliably execute tasks in a timely manner. An appropriate number of {kib} instances can be estimated to match the required scale. +By <>, you can estimate the number of {kib} instances required to reliably execute tasks in a timely manner. An appropriate number of {kib} instances can be estimated to match the required scale. For details on monitoring the health of {kib} Task Manager, follow the guidance in <>. @@ -149,7 +149,7 @@ When evaluating the proposed {kib} instance number under `proposed.provisioned_k By <>, you can make a rough estimate as to the required throughput as a _tasks per minute_ measurement. -For example, suppose your current workload reveals a required throughput of `440/tpm`. You can address this scale by provisioning 3 {kib} instances, with an upper throughput of `600/tpm`. This scale would provide aproximately 25% additional capacity to handle ad-hoc non-recurring tasks and potential growth in recurring tasks. +For example, suppose your current workload reveals a required throughput of `440/tpm`. You can address this scale by provisioning 3 {kib} instances, with an upper throughput of `600/tpm`. This scale would provide approximately 25% additional capacity to handle ad-hoc non-recurring tasks and potential growth in recurring tasks. Given a deployment of 100 recurring tasks, estimating the required throughput depends on the scheduled cadence. Suppose you expect to run 50 tasks at a cadence of `10s`, the other 50 tasks at `20m`. In addition, you expect a couple dozen non-recurring tasks every minute. diff --git a/package.json b/package.json index e91f9c1a7ba3d5..705d902d6afef4 100644 --- a/package.json +++ b/package.json @@ -117,8 +117,8 @@ "@hapi/boom": "^9.1.4", "@hapi/cookie": "^11.0.2", "@hapi/h2o2": "^9.1.0", - "@hapi/hapi": "^20.2.0", - "@hapi/hoek": "^9.2.0", + "@hapi/hapi": "^20.2.1", + "@hapi/hoek": "^9.2.1", "@hapi/inert": "^6.0.4", "@hapi/wreck": "^17.1.0", "@kbn/ace": "link:bazel-bin/packages/kbn-ace", @@ -168,7 +168,7 @@ "@mapbox/mapbox-gl-draw": "1.3.0", "@mapbox/mapbox-gl-rtl-text": "0.2.3", "@mapbox/vector-tile": "1.3.1", - "@reduxjs/toolkit": "^1.5.1", + "@reduxjs/toolkit": "^1.6.1", "@slack/webhook": "^5.0.4", "@turf/along": "6.0.1", "@turf/area": "6.0.1", @@ -252,7 +252,7 @@ "i18n-iso-countries": "^4.3.1", "icalendar": "0.7.1", "idx": "^2.5.6", - "immer": "^8.0.1", + "immer": "^9.0.6", "inline-style": "^2.0.0", "intl": "^1.2.5", "intl-format-cache": "^2.1.0", @@ -356,7 +356,7 @@ "reactcss": "1.2.3", "recompose": "^0.26.0", "reduce-reducers": "^1.0.4", - "redux": "^4.0.5", + "redux": "^4.1.0", "redux-actions": "^2.6.5", "redux-devtools-extension": "^2.13.8", "redux-logger": "^3.0.6", @@ -414,19 +414,19 @@ }, "devDependencies": { "@babel/cli": "^7.15.7", - "@babel/core": "^7.15.5", - "@babel/eslint-parser": "^7.15.7", + "@babel/core": "^7.15.8", + "@babel/eslint-parser": "^7.15.8", "@babel/eslint-plugin": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/parser": "^7.15.7", + "@babel/generator": "^7.15.8", + "@babel/parser": "^7.15.8", "@babel/plugin-proposal-class-properties": "^7.14.5", "@babel/plugin-proposal-export-namespace-from": "^7.14.5", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5", "@babel/plugin-proposal-object-rest-spread": "^7.15.6", "@babel/plugin-proposal-optional-chaining": "^7.14.5", "@babel/plugin-proposal-private-methods": "^7.14.5", - "@babel/plugin-transform-runtime": "^7.15.0", - "@babel/preset-env": "^7.15.6", + "@babel/plugin-transform-runtime": "^7.15.8", + "@babel/preset-env": "^7.15.8", "@babel/preset-react": "^7.14.5", "@babel/preset-typescript": "^7.15.0", "@babel/register": "^7.15.3", diff --git a/packages/kbn-cli-dev-mode/src/optimizer.test.ts b/packages/kbn-cli-dev-mode/src/optimizer.test.ts index ee8ea5f38ae84f..e1763ab4c47568 100644 --- a/packages/kbn-cli-dev-mode/src/optimizer.test.ts +++ b/packages/kbn-cli-dev-mode/src/optimizer.test.ts @@ -18,9 +18,11 @@ import { Optimizer, Options } from './optimizer'; jest.mock('@kbn/optimizer'); const realOptimizer = jest.requireActual('@kbn/optimizer'); -const { runOptimizer, OptimizerConfig, logOptimizerState } = jest.requireMock('@kbn/optimizer'); +const { runOptimizer, OptimizerConfig, logOptimizerState, logOptimizerProgress } = + jest.requireMock('@kbn/optimizer'); logOptimizerState.mockImplementation(realOptimizer.logOptimizerState); +logOptimizerProgress.mockImplementation(realOptimizer.logOptimizerProgress); class MockOptimizerConfig {} diff --git a/packages/kbn-cli-dev-mode/src/optimizer.ts b/packages/kbn-cli-dev-mode/src/optimizer.ts index fab566829f7a6a..3f7a6edc223141 100644 --- a/packages/kbn-cli-dev-mode/src/optimizer.ts +++ b/packages/kbn-cli-dev-mode/src/optimizer.ts @@ -18,7 +18,13 @@ import { } from '@kbn/dev-utils'; import * as Rx from 'rxjs'; import { ignoreElements } from 'rxjs/operators'; -import { runOptimizer, OptimizerConfig, logOptimizerState, OptimizerUpdate } from '@kbn/optimizer'; +import { + runOptimizer, + OptimizerConfig, + logOptimizerState, + logOptimizerProgress, + OptimizerUpdate, +} from '@kbn/optimizer'; export interface Options { enabled: boolean; @@ -111,6 +117,7 @@ export class Optimizer { subscriber.add( runOptimizer(config) .pipe( + logOptimizerProgress(log), logOptimizerState(log, config), tap(({ state }) => { this.phase$.next(state.phase); diff --git a/packages/kbn-dev-utils/src/ci_stats_reporter/ci_stats_reporter.ts b/packages/kbn-dev-utils/src/ci_stats_reporter/ci_stats_reporter.ts index 45d31c1eefad96..fe48ce99e68572 100644 --- a/packages/kbn-dev-utils/src/ci_stats_reporter/ci_stats_reporter.ts +++ b/packages/kbn-dev-utils/src/ci_stats_reporter/ci_stats_reporter.ts @@ -13,6 +13,8 @@ import Path from 'path'; import crypto from 'crypto'; import execa from 'execa'; import Axios from 'axios'; +// @ts-expect-error not "public", but necessary to prevent Jest shimming from breaking things +import httpAdapter from 'axios/lib/adapters/http'; import { ToolingLog } from '../tooling_log'; import { parseConfig, Config } from './ci_stats_config'; @@ -225,6 +227,7 @@ export class CiStatsReporter { baseURL: BASE_URL, headers, data: body, + adapter: httpAdapter, }); return true; diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index a0ca88e4e04bd9..acef661d93bb06 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -64,7 +64,6 @@ pageLoadAssetSize: savedObjectsTaggingOss: 20590 searchprofiler: 67080 security: 95864 - securityOss: 30806 share: 99061 snapshotRestore: 79032 spaces: 57868 @@ -81,7 +80,6 @@ pageLoadAssetSize: usageCollection: 39762 visDefaultEditor: 50178 visTypeMarkdown: 30896 - visTypeMetric: 42790 visTypeTable: 94934 visTypeTagcloud: 37575 visTypeTimelion: 68883 @@ -116,4 +114,6 @@ pageLoadAssetSize: expressions: 239290 securitySolution: 231753 customIntegrations: 28810 + expressionMetricVis: 23121 + visTypeMetric: 23332 dataViews: 42000 diff --git a/packages/kbn-optimizer/src/cli.ts b/packages/kbn-optimizer/src/cli.ts index d5b9996dfb2cd2..7f0c39ccd0e55e 100644 --- a/packages/kbn-optimizer/src/cli.ts +++ b/packages/kbn-optimizer/src/cli.ts @@ -13,6 +13,7 @@ import { lastValueFrom } from '@kbn/std'; import { run, createFlagError, Flags } from '@kbn/dev-utils'; import { logOptimizerState } from './log_optimizer_state'; +import { logOptimizerProgress } from './log_optimizer_progress'; import { OptimizerConfig } from './optimizer'; import { runOptimizer } from './run_optimizer'; import { validateLimitsForAllBundles, updateBundleLimits } from './limits'; @@ -97,6 +98,11 @@ export function runKbnOptimizerCli(options: { defaultLimitsPath: string }) { throw createFlagError('expected --report-stats to have no value'); } + const logProgress = flags.progress ?? false; + if (typeof logProgress !== 'boolean') { + throw createFlagError('expected --progress to have no value'); + } + const filter = typeof flags.filter === 'string' ? [flags.filter] : flags.filter; if (!Array.isArray(filter) || !filter.every((f) => typeof f === 'string')) { throw createFlagError('expected --filter to be one or more strings'); @@ -144,7 +150,11 @@ export function runKbnOptimizerCli(options: { defaultLimitsPath: string }) { const update$ = runOptimizer(config); await lastValueFrom( - update$.pipe(logOptimizerState(log, config), reportOptimizerTimings(log, config)) + update$.pipe( + logProgress ? logOptimizerProgress(log) : (x) => x, + logOptimizerState(log, config), + reportOptimizerTimings(log, config) + ) ); if (updateLimits) { @@ -169,6 +179,7 @@ export function runKbnOptimizerCli(options: { defaultLimitsPath: string }) { 'inspect-workers', 'validate-limits', 'update-limits', + 'progress', ], string: ['workers', 'scan-dir', 'filter', 'limits'], default: { @@ -176,12 +187,14 @@ export function runKbnOptimizerCli(options: { defaultLimitsPath: string }) { examples: true, cache: true, 'inspect-workers': true, + progress: true, filter: [], focus: [], }, help: ` --watch run the optimizer in watch mode --workers max number of workers to use + --no-progress disable logging of progress information --oss only build oss plugins --profile profile the webpack builds and write stats.json files to build outputs --no-core disable generating the core bundle diff --git a/packages/kbn-optimizer/src/index.ts b/packages/kbn-optimizer/src/index.ts index a5838a8a0fac8e..d5e810d584d29f 100644 --- a/packages/kbn-optimizer/src/index.ts +++ b/packages/kbn-optimizer/src/index.ts @@ -9,6 +9,7 @@ export { OptimizerConfig } from './optimizer'; export * from './run_optimizer'; export * from './log_optimizer_state'; +export * from './log_optimizer_progress'; export * from './node'; export * from './limits'; export * from './cli'; diff --git a/packages/kbn-optimizer/src/log_optimizer_progress.ts b/packages/kbn-optimizer/src/log_optimizer_progress.ts new file mode 100644 index 00000000000000..d07c9dc6eff32e --- /dev/null +++ b/packages/kbn-optimizer/src/log_optimizer_progress.ts @@ -0,0 +1,62 @@ +/* + * 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 { ToolingLog } from '@kbn/dev-utils'; +import * as Rx from 'rxjs'; +import { tap } from 'rxjs/operators'; + +import { OptimizerUpdate } from './run_optimizer'; + +const PROGRESS_REPORT_INTERVAL = 10_000; + +export function logOptimizerProgress( + log: ToolingLog +): Rx.MonoTypeOperatorFunction { + return (update$) => + new Rx.Observable((subscriber) => { + const allBundleIds = new Set(); + const completeBundles = new Set(); + let loggedCompletion = new Set(); + + // catalog bundle ids and which have completed at least once, forward + // updates to next subscriber + subscriber.add( + update$ + .pipe( + tap(({ state }) => { + for (const { bundleId, type } of state.compilerStates) { + allBundleIds.add(bundleId); + if (type !== 'running') { + completeBundles.add(bundleId); + } + } + }), + tap(subscriber) + ) + .subscribe() + ); + + // on interval check to see if at least 3 new bundles have completed at + // least one build and log about our progress if so + subscriber.add( + Rx.interval(PROGRESS_REPORT_INTERVAL).subscribe( + () => { + if (completeBundles.size - loggedCompletion.size < 3) { + return; + } + + log.info( + `[${completeBundles.size}/${allBundleIds.size}] initial bundle builds complete` + ); + loggedCompletion = new Set(completeBundles); + }, + (error) => subscriber.error(error) + ) + ); + }); +} diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index 61f6406255a8c3..517e3bbfa51331 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -82,14 +82,11 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { continue; } + bundleStates.set(id, type); + if (type === 'running') { bundlesThatWereBuilt.add(id); } - - bundleStates.set(id, type); - log.debug( - `[${id}] state = "${type}"${type !== 'running' ? ` after ${state.durSec} sec` : ''}` - ); } if (state.phase === 'running' || state.phase === 'initializing') { diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index cab1f6d916f021..f3956363791415 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -8965,6 +8965,8 @@ var _execa = _interopRequireDefault(__webpack_require__(134)); var _axios = _interopRequireDefault(__webpack_require__(177)); +var _http = _interopRequireDefault(__webpack_require__(199)); + var _ci_stats_config = __webpack_require__(218); /* @@ -8974,6 +8976,7 @@ var _ci_stats_config = __webpack_require__(218); * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ +// @ts-expect-error not "public", but necessary to prevent Jest shimming from breaking things const BASE_URL = 'https://ci-stats.kibana.dev'; class CiStatsReporter { @@ -9173,7 +9176,8 @@ class CiStatsReporter { url: path, baseURL: BASE_URL, headers, - data: body + data: body, + adapter: _http.default }); return true; } catch (error) { diff --git a/packages/kbn-test/src/failed_tests_reporter/get_failures.ts b/packages/kbn-test/src/failed_tests_reporter/get_failures.ts index 45c7261e0fd9b5..bb9ea6a425246e 100644 --- a/packages/kbn-test/src/failed_tests_reporter/get_failures.ts +++ b/packages/kbn-test/src/failed_tests_reporter/get_failures.ts @@ -14,6 +14,8 @@ export type TestFailure = FailedTestCase['$'] & { failure: string; likelyIrrelevant: boolean; 'system-out'?: string; + githubIssue?: string; + failureCount?: number; }; const getText = (node?: Array) => { diff --git a/packages/kbn-test/src/failed_tests_reporter/report_failures_to_file.ts b/packages/kbn-test/src/failed_tests_reporter/report_failures_to_file.ts index f075f6ef0b75b2..e481da019945c6 100644 --- a/packages/kbn-test/src/failed_tests_reporter/report_failures_to_file.ts +++ b/packages/kbn-test/src/failed_tests_reporter/report_failures_to_file.ts @@ -82,13 +82,19 @@ export function reportFailuresToFile(log: ToolingLog, failures: TestFailure[]) { ? ` #${parseInt(process.env.BUILDKITE_PARALLEL_JOB, 10) + 1}` : ''; + const buildUrl = process.env.BUILDKITE_BUILD_URL || ''; + const jobUrl = process.env.BUILDKITE_JOB_ID + ? `${buildUrl}#${process.env.BUILDKITE_JOB_ID}` + : ''; + const failureJSON = JSON.stringify( { ...failure, hash, buildId: process.env.BUJILDKITE_BUILD_ID || '', jobId: process.env.BUILDKITE_JOB_ID || '', - url: process.env.BUILDKITE_BUILD_URL || '', + url: buildUrl, + jobUrl, jobName: process.env.BUILDKITE_LABEL ? `${process.env.BUILDKITE_LABEL}${jobNumberSuffix}` : '', @@ -128,6 +134,30 @@ export function reportFailuresToFile(log: ToolingLog, failures: TestFailure[]) { .join('')}

${escape(failure.name)}

+

+ + Failures in tracked branches: ${ + failure.failureCount || 0 + } + ${ + failure.githubIssue + ? `
${escape( + failure.githubIssue + )}` + : '' + } +
+

+ ${ + jobUrl + ? `

+ + Buildkite Job
+ ${escape(jobUrl)} +
+

` + : '' + }
${escape(failure.failure)}
${screenshotHtml}
${escape(failure['system-out'] || '')}
diff --git a/packages/kbn-test/src/failed_tests_reporter/run_failed_tests_reporter_cli.ts b/packages/kbn-test/src/failed_tests_reporter/run_failed_tests_reporter_cli.ts index 31cd43eae4141a..80fe8340e6a11b 100644 --- a/packages/kbn-test/src/failed_tests_reporter/run_failed_tests_reporter_cli.ts +++ b/packages/kbn-test/src/failed_tests_reporter/run_failed_tests_reporter_cli.ts @@ -99,8 +99,6 @@ export function runFailedTestsReporterCli() { const messages = Array.from(getReportMessageIter(report)); const failures = await getFailures(report); - reportFailuresToFile(log, failures); - if (indexInEs) { await reportFailuresToEs(log, failures); } @@ -146,6 +144,8 @@ export function runFailedTestsReporterCli() { branch ); const url = existingIssue.html_url; + failure.githubIssue = url; + failure.failureCount = updateGithub ? newFailureCount : newFailureCount - 1; pushMessage(`Test has failed ${newFailureCount - 1} times on tracked branches: ${url}`); if (updateGithub) { pushMessage(`Updated existing issue: ${url} (fail count: ${newFailureCount})`); @@ -157,8 +157,10 @@ export function runFailedTestsReporterCli() { pushMessage('Test has not failed recently on tracked branches'); if (updateGithub) { pushMessage(`Created new issue: ${newIssue.html_url}`); + failure.githubIssue = newIssue.html_url; } newlyCreatedIssues.push({ failure, newIssue }); + failure.failureCount = updateGithub ? 1 : 0; } // mutates report to include messages and writes updated report to disk @@ -169,6 +171,8 @@ export function runFailedTestsReporterCli() { reportPath, dryRun: !flags['report-update'], }); + + reportFailuresToFile(log, failures); } }, { diff --git a/scripts/functional_tests.js b/scripts/functional_tests.js index 032a28477bc903..89f20121867dc7 100644 --- a/scripts/functional_tests.js +++ b/scripts/functional_tests.js @@ -12,7 +12,6 @@ const alwaysImportedTests = [ require.resolve('../test/plugin_functional/config.ts'), require.resolve('../test/ui_capabilities/newsfeed_err/config.ts'), require.resolve('../test/new_visualize_flow/config.ts'), - require.resolve('../test/security_functional/config.ts'), ]; // eslint-disable-next-line no-restricted-syntax const onlyNotInCoverageTests = [ diff --git a/src/core/public/application/types.ts b/src/core/public/application/types.ts index 5803f2e3779abc..94930f55b8b2c3 100644 --- a/src/core/public/application/types.ts +++ b/src/core/public/application/types.ts @@ -83,7 +83,7 @@ export interface AppNavOptions { /** * A EUI iconType that will be used for the app's icon. This icon - * takes precendence over the `icon` property. + * takes precedence over the `icon` property. */ euiIconType?: string; diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index 9a9b7aabc4decb..01108298adc992 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -25,6 +25,7 @@ export class DocLinksService { const FLEET_DOCS = `${ELASTIC_WEBSITE_URL}guide/en/fleet/${DOC_LINK_VERSION}/`; const PLUGIN_DOCS = `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/plugins/${DOC_LINK_VERSION}/`; const APM_DOCS = `${ELASTIC_WEBSITE_URL}guide/en/apm/`; + const SECURITY_SOLUTION_DOCS = `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/`; return deepFreeze({ DOC_LINK_VERSION, @@ -223,13 +224,14 @@ export class DocLinksService { typesRemoval: `${ELASTICSEARCH_DOCS}removal-of-types.html`, }, siem: { - guide: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/index.html`, - gettingStarted: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/index.html`, - privileges: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/sec-requirements.html`, - ml: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/machine-learning.html`, - ruleChangeLog: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/prebuilt-rules-changelog.html`, - detectionsReq: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/detections-permissions-section.html`, - networkMap: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/conf-map-ui.html`, + guide: `${SECURITY_SOLUTION_DOCS}index.html`, + gettingStarted: `${SECURITY_SOLUTION_DOCS}index.html`, + privileges: `${SECURITY_SOLUTION_DOCS}sec-requirements.html`, + ml: `${SECURITY_SOLUTION_DOCS}machine-learning.html`, + ruleChangeLog: `${SECURITY_SOLUTION_DOCS}prebuilt-rules-changelog.html`, + detectionsReq: `${SECURITY_SOLUTION_DOCS}detections-permissions-section.html`, + networkMap: `${SECURITY_SOLUTION_DOCS}conf-map-ui.html`, + troubleshootGaps: `${SECURITY_SOLUTION_DOCS}alerts-ui-monitor.html#troubleshoot-gaps`, }, query: { eql: `${ELASTICSEARCH_DOCS}eql.html`, @@ -356,6 +358,10 @@ export class DocLinksService { mappingRolesFieldRules: `${ELASTICSEARCH_DOCS}role-mapping-resources.html#mapping-roles-rule-field`, runAsPrivilege: `${ELASTICSEARCH_DOCS}security-privileges.html#_run_as_privilege`, }, + spaces: { + kibanaLegacyUrlAliases: `${KIBANA_DOCS}legacy-url-aliases.html`, + kibanaDisableLegacyUrlAliasesApi: `${KIBANA_DOCS}spaces-api-disable-legacy-url-aliases.html`, + }, watcher: { jiraAction: `${ELASTICSEARCH_DOCS}actions-jira.html`, pagerDutyAction: `${ELASTICSEARCH_DOCS}actions-pagerduty.html`, @@ -470,6 +476,7 @@ export class DocLinksService { datastreamsNamingScheme: `${FLEET_DOCS}data-streams.html#data-streams-naming-scheme`, upgradeElasticAgent: `${FLEET_DOCS}upgrade-elastic-agent.html`, upgradeElasticAgent712lower: `${FLEET_DOCS}upgrade-elastic-agent.html#upgrade-7.12-lower`, + learnMoreBlog: `${ELASTIC_WEBSITE_URL}blog/elastic-agent-and-fleet-make-it-easier-to-integrate-your-systems-with-elastic`, }, ecs: { guide: `${ELASTIC_WEBSITE_URL}guide/en/ecs/current/index.html`, @@ -632,6 +639,7 @@ export interface DocLinksStart { readonly ruleChangeLog: string; readonly detectionsReq: string; readonly networkMap: string; + readonly troubleshootGaps: string; }; readonly query: { readonly eql: string; @@ -702,6 +710,10 @@ export interface DocLinksStart { mappingRolesFieldRules: string; runAsPrivilege: string; }>; + readonly spaces: Readonly<{ + kibanaLegacyUrlAliases: string; + kibanaDisableLegacyUrlAliasesApi: string; + }>; readonly watcher: Record; readonly ccs: Record; readonly plugins: Record; @@ -719,6 +731,7 @@ export interface DocLinksStart { datastreamsNamingScheme: string; upgradeElasticAgent: string; upgradeElasticAgent712lower: string; + learnMoreBlog: string; }>; readonly ecs: { readonly guide: string; diff --git a/src/core/public/http/types.ts b/src/core/public/http/types.ts index 3eb718b318f86d..4d59c52813e182 100644 --- a/src/core/public/http/types.ts +++ b/src/core/public/http/types.ts @@ -32,7 +32,7 @@ export interface HttpSetup { */ intercept(interceptor: HttpInterceptor): () => void; - /** Makes an HTTP request. Defaults to a GET request unless overriden. See {@link HttpHandler} for options. */ + /** Makes an HTTP request. Defaults to a GET request unless overridden. See {@link HttpHandler} for options. */ fetch: HttpHandler; /** Makes an HTTP request with the DELETE method. See {@link HttpHandler} for options. */ delete: HttpHandler; diff --git a/src/core/public/notifications/toasts/global_toast_list.tsx b/src/core/public/notifications/toasts/global_toast_list.tsx index 081d97bc2071e9..6e1ab11601d7e1 100644 --- a/src/core/public/notifications/toasts/global_toast_list.tsx +++ b/src/core/public/notifications/toasts/global_toast_list.tsx @@ -58,7 +58,7 @@ export class GlobalToastList extends React.Component { toasts={this.state.toasts.map(convertToEui)} dismissToast={({ id }) => this.props.dismissToast(id)} /** - * This prop is overriden by the individual toasts that are added. + * This prop is overridden by the individual toasts that are added. * Use `Infinity` here so that it's obvious a timeout hasn't been * provided in development. */ diff --git a/src/core/public/plugins/plugin_context.ts b/src/core/public/plugins/plugin_context.ts index 3461f570333d52..f87f07d553e0c8 100644 --- a/src/core/public/plugins/plugin_context.ts +++ b/src/core/public/plugins/plugin_context.ts @@ -34,7 +34,7 @@ export interface PluginInitializerContext } /** - * Provides a plugin-specific context passed to the plugin's construtor. This is currently + * Provides a plugin-specific context passed to the plugin's constructor. This is currently * empty but should provide static services in the future, such as config and logging. * * @param coreContext diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 7871558574074c..45b7e3bdc02b5c 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -612,6 +612,7 @@ export interface DocLinksStart { readonly ruleChangeLog: string; readonly detectionsReq: string; readonly networkMap: string; + readonly troubleshootGaps: string; }; readonly query: { readonly eql: string; @@ -682,6 +683,10 @@ export interface DocLinksStart { mappingRolesFieldRules: string; runAsPrivilege: string; }>; + readonly spaces: Readonly<{ + kibanaLegacyUrlAliases: string; + kibanaDisableLegacyUrlAliasesApi: string; + }>; readonly watcher: Record; readonly ccs: Record; readonly plugins: Record; @@ -699,6 +704,7 @@ export interface DocLinksStart { datastreamsNamingScheme: string; upgradeElasticAgent: string; upgradeElasticAgent712lower: string; + learnMoreBlog: string; }>; readonly ecs: { readonly guide: string; diff --git a/src/core/server/core_usage_data/index.ts b/src/core/server/core_usage_data/index.ts index 4687446bdb3a31..186ad95cbdca22 100644 --- a/src/core/server/core_usage_data/index.ts +++ b/src/core/server/core_usage_data/index.ts @@ -19,7 +19,7 @@ export type { export { CoreUsageDataService } from './core_usage_data_service'; export { CoreUsageStatsClient, REPOSITORY_RESOLVE_OUTCOME_STATS } from './core_usage_stats_client'; -// Because of #79265 we need to explicity import, then export these types for +// Because of #79265 we need to explicitly import, then export these types for // scripts/telemetry_check.js to work as expected import { CoreUsageStats, diff --git a/src/core/server/deprecations/README.mdx b/src/core/server/deprecations/README.mdx index 533f607c3d4c22..82a01995502e24 100644 --- a/src/core/server/deprecations/README.mdx +++ b/src/core/server/deprecations/README.mdx @@ -252,7 +252,7 @@ Examples: > become read-only if disk usage reaches 95%. ## Note on i18n -All deprecation titles, messsages, and manual steps should be wrapped in `i18n.translate`. This +All deprecation titles, messages, and manual steps should be wrapped in `i18n.translate`. This provides a better user experience using different locales. Follow the writing guidelines below for best practices to writing the i18n messages and ids. diff --git a/src/core/server/deprecations/deprecations_service.test.ts b/src/core/server/deprecations/deprecations_service.test.ts index 0067cff1d23069..dfc1c852f773ef 100644 --- a/src/core/server/deprecations/deprecations_service.test.ts +++ b/src/core/server/deprecations/deprecations_service.test.ts @@ -78,7 +78,7 @@ describe('DeprecationsService', () => { correctiveActions: { manualSteps: [ 'Using Kibana user management, change all users using the kibana_user role to the kibana_admin role.', - 'Using Kibana role-mapping management, change all role-mappings which assing the kibana_user role to the kibana_admin role.', + 'Using Kibana role-mapping management, change all role-mappings which assign the kibana_user role to the kibana_admin role.', ], }, }, @@ -103,7 +103,7 @@ describe('DeprecationsService', () => { "correctiveActions": Object { "manualSteps": Array [ "Using Kibana user management, change all users using the kibana_user role to the kibana_admin role.", - "Using Kibana role-mapping management, change all role-mappings which assing the kibana_user role to the kibana_admin role.", + "Using Kibana role-mapping management, change all role-mappings which assign the kibana_user role to the kibana_admin role.", ], }, "deprecationType": "config", diff --git a/src/core/server/environment/resolve_uuid.ts b/src/core/server/environment/resolve_uuid.ts index 74201a7ffa04ff..15c67d027bd837 100644 --- a/src/core/server/environment/resolve_uuid.ts +++ b/src/core/server/environment/resolve_uuid.ts @@ -16,7 +16,7 @@ import { Logger } from '../logging'; const FILE_ENCODING = 'utf8'; const FILE_NAME = 'uuid'; /** - * This UUID was inadvertantly shipped in the 7.6.0 distributable and should be deleted if found. + * This UUID was inadvertently shipped in the 7.6.0 distributable and should be deleted if found. * See https://github.com/elastic/kibana/issues/57673 for more info. */ export const UUID_7_6_0_BUG = `ce42b997-a913-4d58-be46-bb1937feedd6`; diff --git a/src/core/server/execution_context/execution_context_container.test.ts b/src/core/server/execution_context/execution_context_container.test.ts index 41095815a6b44b..c332913b2f4015 100644 --- a/src/core/server/execution_context/execution_context_container.test.ts +++ b/src/core/server/execution_context/execution_context_container.test.ts @@ -115,7 +115,7 @@ describe('KibanaExecutionContext', () => { expect(value).toEqual(context); }); - it('returns a context object with registed parent object', () => { + it('returns a context object with registered parent object', () => { const parentContext: KibanaExecutionContext = { type: 'parent-type', name: 'parent-name', diff --git a/src/core/server/execution_context/integration_tests/tracing.test.ts b/src/core/server/execution_context/integration_tests/tracing.test.ts index f07546d44e956a..c8dccc2ae9c42e 100644 --- a/src/core/server/execution_context/integration_tests/tracing.test.ts +++ b/src/core/server/execution_context/integration_tests/tracing.test.ts @@ -132,7 +132,7 @@ describe('trace', () => { expect(header).toEqual(expect.any(String)); }); - it('can be overriden during Elasticsearch client call', async () => { + it('can be overridden during Elasticsearch client call', async () => { const { http } = await root.setup(); const { createRouter } = http; diff --git a/src/core/server/http/lifecycle_handlers.test.ts b/src/core/server/http/lifecycle_handlers.test.ts index e777cbb1c1ff07..23dbf6c3540164 100644 --- a/src/core/server/http/lifecycle_handlers.test.ts +++ b/src/core/server/http/lifecycle_handlers.test.ts @@ -266,7 +266,7 @@ describe('customHeaders pre-response handler', () => { }); }); - it('preserve the kbn-name value from server.name if definied in custom headders ', () => { + it('preserve the kbn-name value from server.name if defined in custom headders ', () => { const config = createConfig({ name: 'my-server-name', customResponseHeaders: { diff --git a/src/core/server/logging/appenders/rolling_file/rolling_file_appender.ts b/src/core/server/logging/appenders/rolling_file/rolling_file_appender.ts index 452d9493359544..3848ecbd1b03d9 100644 --- a/src/core/server/logging/appenders/rolling_file/rolling_file_appender.ts +++ b/src/core/server/logging/appenders/rolling_file/rolling_file_appender.ts @@ -144,7 +144,7 @@ export class RollingFileAppender implements DisposableAppender { // this would cause a second rollover that would not be awaited // and could result in a race with the newly created appender // that would also be performing a rollover. - // so if we are disposed, we just flush the buffer directly to the file instead to avoid loosing the entries. + // so if we are disposed, we just flush the buffer directly to the file instead to avoid losing the entries. for (const log of pendingLogs) { if (this.disposed) { this._writeToFile(log); diff --git a/src/core/server/saved_objects/export/errors.ts b/src/core/server/saved_objects/export/errors.ts index 32a78330f86d51..0110e68142fa0b 100644 --- a/src/core/server/saved_objects/export/errors.ts +++ b/src/core/server/saved_objects/export/errors.ts @@ -40,7 +40,7 @@ export class SavedObjectsExportError extends Error { } /** - * Error returned when a {@link SavedObjectsExportTransform | export tranform} threw an error + * Error returned when a {@link SavedObjectsExportTransform | export transform} threw an error */ static objectTransformError(objects: SavedObject[], cause: Error) { return new SavedObjectsExportError( @@ -54,7 +54,7 @@ export class SavedObjectsExportError extends Error { } /** - * Error returned when a {@link SavedObjectsExportTransform | export tranform} performed an invalid operation + * Error returned when a {@link SavedObjectsExportTransform | export transform} performed an invalid operation * during the transform, such as removing objects from the export, or changing an object's type or id. */ static invalidTransformError(objectKeys: string[]) { diff --git a/src/core/server/saved_objects/import/resolve_import_errors.ts b/src/core/server/saved_objects/import/resolve_import_errors.ts index bf28e9c37d9bad..25382965e845bd 100644 --- a/src/core/server/saved_objects/import/resolve_import_errors.ts +++ b/src/core/server/saved_objects/import/resolve_import_errors.ts @@ -52,7 +52,7 @@ export interface ResolveSavedObjectsImportErrorsOptions { /** * Resolve and return saved object import errors. - * See the {@link SavedObjectsResolveImportErrorsOptions | options} for more detailed informations. + * See the {@link SavedObjectsResolveImportErrorsOptions | options} for more detailed information. * * @public */ diff --git a/src/core/server/saved_objects/import/saved_objects_importer.ts b/src/core/server/saved_objects/import/saved_objects_importer.ts index 5659a53091e2dc..f4572e58d6fadf 100644 --- a/src/core/server/saved_objects/import/saved_objects_importer.ts +++ b/src/core/server/saved_objects/import/saved_objects_importer.ts @@ -81,7 +81,7 @@ export class SavedObjectsImporter { /** * Resolve and return saved object import errors. - * See the {@link SavedObjectsResolveImportErrorsOptions | options} for more detailed informations. + * See the {@link SavedObjectsResolveImportErrorsOptions | options} for more detailed information. * * @throws SavedObjectsImportError */ diff --git a/src/core/server/saved_objects/migrations/README.md b/src/core/server/saved_objects/migrations/README.md index 7db0b38773a67b..69331c3751c8e6 100644 --- a/src/core/server/saved_objects/migrations/README.md +++ b/src/core/server/saved_objects/migrations/README.md @@ -44,7 +44,7 @@ It might happen that a user modifies their FanciPlugin 1.0 export file to have d Similarly, Kibana server APIs assume that they are sent up to date documents unless a document specifies a migrationVersion. This means that out-of-date callers of our APIs will send us out-of-date documents, and those documents will be accepted and stored as if they are up-to-date. -To prevent this from happening, migration authors should _always_ write a [validation](../validation) function that throws an error if a document is not up to date, and this validation function should always be updated any time a new migration is added for the relevent document types. +To prevent this from happening, migration authors should _always_ write a [validation](../validation) function that throws an error if a document is not up to date, and this validation function should always be updated any time a new migration is added for the relevant document types. ## Document ownership @@ -92,7 +92,7 @@ Each migration function only needs to be able to handle documents belonging to t ## Disabled plugins -If a plugin is disbled, all of its documents are retained in the Kibana index. They can be imported and exported. When the plugin is re-enabled, Kibana will migrate any out of date documents that were imported or retained while it was disabled. +If a plugin is disabled, all of its documents are retained in the Kibana index. They can be imported and exported. When the plugin is re-enabled, Kibana will migrate any out of date documents that were imported or retained while it was disabled. ## Configuration @@ -116,7 +116,7 @@ Kibana index migrations expose a few config settings which might be tweaked: To illustrate how migrations work, let's walk through an example, using a fictional plugin: `FanciPlugin`. -FanciPlugin 1.0 had a mappping that looked like this: +FanciPlugin 1.0 had a mapping that looked like this: ```js { diff --git a/src/core/server/saved_objects/migrations/core/document_migrator.ts b/src/core/server/saved_objects/migrations/core/document_migrator.ts index 040aa81cdab3a7..da16dbc5e69e8d 100644 --- a/src/core/server/saved_objects/migrations/core/document_migrator.ts +++ b/src/core/server/saved_objects/migrations/core/document_migrator.ts @@ -443,7 +443,7 @@ function buildDocumentTransform({ } // In order to keep tests a bit more stable, we won't - // tack on an empy migrationVersion to docs that have + // tack on an empty migrationVersion to docs that have // no migrations defined. if (_.isEmpty(transformedDoc.migrationVersion)) { delete transformedDoc.migrationVersion; @@ -740,7 +740,7 @@ function nextUnmigratedProp(doc: SavedObjectUnsanitizedDoc, migrations: ActiveMi } /** - * Applies any relevent migrations to the document for the specified property. + * Applies any relevant migrations to the document for the specified property. */ function migrateProp( doc: SavedObjectUnsanitizedDoc, diff --git a/src/core/server/saved_objects/migrations/core/migration_context.test.ts b/src/core/server/saved_objects/migrations/core/migration_context.test.ts index 27aae5968ba881..0ca858c34e8bac 100644 --- a/src/core/server/saved_objects/migrations/core/migration_context.test.ts +++ b/src/core/server/saved_objects/migrations/core/migration_context.test.ts @@ -62,7 +62,7 @@ describe('disableUnknownTypeMappingFields', () => { properties: { new_field: { type: 'binary' }, field_1: { type: 'keyword' }, // was type text in source mappings - // old_field was present in source but ommited in active mappings + // old_field was present in source but omitted in active mappings }, }); }); diff --git a/src/core/server/saved_objects/migrationsv2/actions/update_aliases.ts b/src/core/server/saved_objects/migrationsv2/actions/update_aliases.ts index 5f1903f010a411..f76d30ae023db2 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/update_aliases.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/update_aliases.ts @@ -67,7 +67,7 @@ export const updateAliases = // The only impact for using `updateAliases` to mark the version index // as ready is that it could take longer for other Kibana instances to // see that the version index is ready so they are more likely to - // perform unecessary duplicate work. + // perform unnecessary duplicate work. return Either.right('update_aliases_succeeded' as const); }) .catch((err: EsErrors.ElasticsearchClientError) => { diff --git a/src/core/server/saved_objects/migrationsv2/actions/wait_for_task.ts b/src/core/server/saved_objects/migrationsv2/actions/wait_for_task.ts index af0ed3613bd6bc..212e1ad9c8c813 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/wait_for_task.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/wait_for_task.ts @@ -23,7 +23,7 @@ export interface WaitForTaskResponse { } /** - * After waiting for the specificed timeout, the task has not yet completed. + * After waiting for the specified timeout, the task has not yet completed. * * When querying the tasks API we use `wait_for_completion=true` to block the * request until the task completes. If after the `timeout`, the task still has @@ -31,7 +31,7 @@ export interface WaitForTaskResponse { * has reached a timeout, Elasticsearch will continue to run the task. */ export interface WaitForTaskCompletionTimeout { - /** After waiting for the specificed timeout, the task has not yet completed. */ + /** After waiting for the specified timeout, the task has not yet completed. */ readonly type: 'wait_for_task_completion_timeout'; readonly message: string; readonly error?: Error; diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/collects_corrupt_docs.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/collects_corrupt_docs.test.ts index 02b7d0eae2a90a..779db252154a34 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/collects_corrupt_docs.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/collects_corrupt_docs.test.ts @@ -40,7 +40,7 @@ describe('migration v2 with corrupt saved object documents', () => { await new Promise((resolve) => setTimeout(resolve, 10000)); }); - it('collects corrupt saved object documents accross batches', async () => { + it('collects corrupt saved object documents across batches', async () => { const { startES } = kbnTestServer.createTestServers({ adjustTimeout: (t: number) => jest.setTimeout(t), settings: { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/corrupt_outdated_docs.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/corrupt_outdated_docs.test.ts index 446542cc37306c..7368d856e2c2c7 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/corrupt_outdated_docs.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/corrupt_outdated_docs.test.ts @@ -40,7 +40,7 @@ describe('migration v2 with corrupt saved object documents', () => { await new Promise((resolve) => setTimeout(resolve, 10000)); }); - it('collects corrupt saved object documents accross batches', async () => { + it('collects corrupt saved object documents across batches', async () => { const { startES } = kbnTestServer.createTestServers({ adjustTimeout: (t: number) => jest.setTimeout(t), settings: { diff --git a/src/core/server/saved_objects/migrationsv2/model/model.test.ts b/src/core/server/saved_objects/migrationsv2/model/model.test.ts index 3e48a7147bffda..e4ab5a0f110397 100644 --- a/src/core/server/saved_objects/migrationsv2/model/model.test.ts +++ b/src/core/server/saved_objects/migrationsv2/model/model.test.ts @@ -565,7 +565,7 @@ describe('migrations v2 model', () => { }); // The createIndex action called by LEGACY_CREATE_REINDEX_TARGET never // returns a left, it will always succeed or timeout. Since timeout - // failures are always retried we don't explicity test this logic + // failures are always retried we don't explicitly test this logic }); describe('LEGACY_REINDEX', () => { diff --git a/src/core/server/saved_objects/migrationsv2/model/model.ts b/src/core/server/saved_objects/migrationsv2/model/model.ts index 5d8862e48df1a2..3c36c668f2d99d 100644 --- a/src/core/server/saved_objects/migrationsv2/model/model.ts +++ b/src/core/server/saved_objects/migrationsv2/model/model.ts @@ -265,7 +265,7 @@ export const model = (currentState: State, resW: ResponseType): // control state progression and simplify the implementation. return { ...stateP, controlState: 'LEGACY_DELETE' }; } else if (isLeftTypeof(left, 'wait_for_task_completion_timeout')) { - // After waiting for the specificed timeout, the task has not yet + // After waiting for the specified timeout, the task has not yet // completed. Retry this step to see if the task has completed after an // exponential delay. We will basically keep polling forever until the // Elasticeasrch task succeeds or fails. @@ -854,7 +854,7 @@ export const model = (currentState: State, resW: ResponseType): } else { // If there are none versionIndexReadyActions another instance // already completed this migration and we only transformed outdated - // documents and updated the mappings for incase a new plugin was + // documents and updated the mappings for in case a new plugin was // enabled. return { ...stateP, diff --git a/src/core/server/saved_objects/saved_objects_service.test.ts b/src/core/server/saved_objects/saved_objects_service.test.ts index 1d860d2c5a6950..7321e760273bfd 100644 --- a/src/core/server/saved_objects/saved_objects_service.test.ts +++ b/src/core/server/saved_objects/saved_objects_service.test.ts @@ -301,7 +301,7 @@ describe('SavedObjectsService', () => { }); describe('#createScopedRepository', () => { - it('creates a respository scoped to the user', async () => { + it('creates a repository scoped to the user', async () => { const coreContext = createCoreContext({ skipMigration: false }); const soService = new SavedObjectsService(coreContext); const coreSetup = createSetupDeps(); @@ -321,7 +321,7 @@ describe('SavedObjectsService', () => { expect(includedHiddenTypes).toEqual([]); }); - it('creates a respository including hidden types when specified', async () => { + it('creates a repository including hidden types when specified', async () => { const coreContext = createCoreContext({ skipMigration: false }); const soService = new SavedObjectsService(coreContext); const coreSetup = createSetupDeps(); @@ -341,7 +341,7 @@ describe('SavedObjectsService', () => { }); describe('#createInternalRepository', () => { - it('creates a respository using the admin user', async () => { + it('creates a repository using the admin user', async () => { const coreContext = createCoreContext({ skipMigration: false }); const soService = new SavedObjectsService(coreContext); const coreSetup = createSetupDeps(); @@ -359,7 +359,7 @@ describe('SavedObjectsService', () => { expect(includedHiddenTypes).toEqual([]); }); - it('creates a respository including hidden types when specified', async () => { + it('creates a repository including hidden types when specified', async () => { const coreContext = createCoreContext({ skipMigration: false }); const soService = new SavedObjectsService(coreContext); const coreSetup = createSetupDeps(); diff --git a/src/core/server/saved_objects/service/lib/internal_bulk_resolve.test.ts b/src/core/server/saved_objects/service/lib/internal_bulk_resolve.test.ts index ea177caf26c9f3..5403e146509ae3 100644 --- a/src/core/server/saved_objects/service/lib/internal_bulk_resolve.test.ts +++ b/src/core/server/saved_objects/service/lib/internal_bulk_resolve.test.ts @@ -243,7 +243,7 @@ describe('internalBulkResolve', () => { }); it('does not call bulk update in the Default space', async () => { - // Aliases cannot exist in the Default space, so we skip the alias check part of the alogrithm in that case (e.g., bulk update) + // Aliases cannot exist in the Default space, so we skip the alias check part of the algorithm in that case (e.g., bulk update) for (const namespace of [undefined, 'default']) { const params = setup([{ type: OBJ_TYPE, id: '1' }], { namespace }); mockMgetResults( diff --git a/src/core/server/saved_objects/service/lib/repository.ts b/src/core/server/saved_objects/service/lib/repository.ts index 9cdc58f02f5d15..7dda0861918e76 100644 --- a/src/core/server/saved_objects/service/lib/repository.ts +++ b/src/core/server/saved_objects/service/lib/repository.ts @@ -1710,7 +1710,7 @@ export class SavedObjectsRepository { return this.incrementCounterInternal(type, id, counterFields, options); } - /** @internal incrementCounter function that is used interally and bypasses validation checks. */ + /** @internal incrementCounter function that is used internally and bypasses validation checks. */ private async incrementCounterInternal( type: string, id: string, @@ -2208,7 +2208,7 @@ const errorContent = (error: DecoratedError) => error.output.payload; const unique = (array: string[]) => [...new Set(array)]; /** - * Type and type guard function for converting a possibly not existant doc to an existant doc. + * Type and type guard function for converting a possibly not existent doc to an existent doc. */ type GetResponseFound = estypes.GetResponse & Required< diff --git a/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts b/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts index f58a91fa087459..a02378390af7db 100644 --- a/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts +++ b/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts @@ -183,7 +183,7 @@ export function getClauseForReference(reference: HasReferenceQueryParams) { }; } -// A de-duplicated set of namespaces makes for a more effecient query. +// A de-duplicated set of namespaces makes for a more efficient query. const uniqNamespaces = (namespacesToNormalize?: string[]) => namespacesToNormalize ? Array.from(new Set(namespacesToNormalize)) : undefined; diff --git a/src/core/server/saved_objects/types.ts b/src/core/server/saved_objects/types.ts index 7e38a52bee0cae..dca8814b2914a1 100644 --- a/src/core/server/saved_objects/types.ts +++ b/src/core/server/saved_objects/types.ts @@ -214,7 +214,7 @@ export type MutatingOperationRefreshSetting = boolean | 'wait_for'; * * From the perspective of application code and APIs the SavedObjectsClient is * a black box that persists objects. One of the internal details that users have - * no control over is that we use an elasticsearch index for persistance and that + * no control over is that we use an elasticsearch index for persistence and that * index might be missing. * * At the time of writing we are in the process of transitioning away from the diff --git a/src/core/server/status/types.ts b/src/core/server/status/types.ts index aab3bf302dfea2..564a2232cc3103 100644 --- a/src/core/server/status/types.ts +++ b/src/core/server/status/types.ts @@ -217,7 +217,7 @@ export interface StatusServiceSetup { * By default, plugins inherit this derived status from their dependencies. * Calling {@link StatusSetup.set} overrides this default status. * - * This may emit multliple times for a single status change event as propagates + * This may emit multiple times for a single status change event as propagates * through the dependency tree */ derivedStatus$: Observable; diff --git a/src/core/server/ui_settings/ui_settings_client.test.ts b/src/core/server/ui_settings/ui_settings_client.test.ts index b73d25b7cf6e05..99ab87610db90e 100644 --- a/src/core/server/ui_settings/ui_settings_client.test.ts +++ b/src/core/server/ui_settings/ui_settings_client.test.ts @@ -603,7 +603,7 @@ describe('ui settings', () => { expect(result).toBe('YYYY-MM-DD'); }); - it('returns the overridden value for an overrided key', async () => { + it('returns the overridden value for an overriden key', async () => { const esDocSource = { dateFormat: 'YYYY-MM-DD' }; const overrides = { dateFormat: 'foo' }; const { uiSettings } = setup({ esDocSource, overrides }); diff --git a/src/dev/build/tasks/os_packages/create_os_package_kibana_yml.ts b/src/dev/build/tasks/os_packages/create_os_package_kibana_yml.ts index be21bc4930591f..ebd62f83798d74 100644 --- a/src/dev/build/tasks/os_packages/create_os_package_kibana_yml.ts +++ b/src/dev/build/tasks/os_packages/create_os_package_kibana_yml.ts @@ -23,7 +23,7 @@ export async function createOSPackageKibanaYML(config: Config, build: Build) { [ [/#pid.file:.*/g, 'pid.file: /run/kibana/kibana.pid'], [ - /#logging.dest:.*/g, + /#logging.appenders.default:.*kibana\.log\n/gs, dump({ logging: { appenders: { diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker index dd5b66af9ef217..f87d1c9664273c 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker @@ -366,6 +366,7 @@ kibana_vars=( xpack.security.session.idleTimeout xpack.security.session.lifespan xpack.security.sessionTimeout + xpack.security.showInsecureClusterWarning xpack.securitySolution.alertMergeStrategy xpack.securitySolution.alertIgnoreFields xpack.securitySolution.endpointResultListDefaultFirstPageIndex diff --git a/src/dev/code_coverage/ingest_coverage/__tests__/enumerate_patterns.test.js b/src/dev/code_coverage/ingest_coverage/__tests__/enumerate_patterns.test.js index fa82641e142d0b..05af7c2a154a4c 100644 --- a/src/dev/code_coverage/ingest_coverage/__tests__/enumerate_patterns.test.js +++ b/src/dev/code_coverage/ingest_coverage/__tests__/enumerate_patterns.test.js @@ -26,13 +26,13 @@ describe(`enumeratePatterns`, () => { ) ).toBe(true); }); - it(`should resolve src/plugins/charts/public/static/color_maps/color_maps.ts to kibana-app`, () => { + it(`should resolve src/plugins/charts/common/static/color_maps/color_maps.ts to kibana-app`, () => { const actual = enumeratePatterns(REPO_ROOT)(log)( - new Map([['src/plugins/charts/public/static/color_maps', ['kibana-app']]]) + new Map([['src/plugins/charts/common/static/color_maps', ['kibana-app']]]) ); expect(actual[0][0]).toBe( - 'src/plugins/charts/public/static/color_maps/color_maps.ts kibana-app' + 'src/plugins/charts/common/static/color_maps/color_maps.ts kibana-app' ); }); it(`should resolve x-pack/plugins/security_solution/public/common/components/exceptions/edit_exception_modal/translations.ts to kibana-security`, () => { diff --git a/src/dev/code_coverage/ingest_coverage/__tests__/transforms.test.js b/src/dev/code_coverage/ingest_coverage/__tests__/transforms.test.js index 60a68253d2c4ea..5e33f2ba548aaf 100644 --- a/src/dev/code_coverage/ingest_coverage/__tests__/transforms.test.js +++ b/src/dev/code_coverage/ingest_coverage/__tests__/transforms.test.js @@ -98,7 +98,7 @@ describe(`Transform fns`, () => { }); }); - describe(`with a coveredFilePath of src/plugins/charts/public/static/color_maps/color_maps.ts`, () => { + describe(`with a coveredFilePath of src/plugins/charts/common/static/color_maps/color_maps.ts`, () => { const expected = 'kibana-reporting'; it(`should resolve to ${expected}`, async () => { const actual = await teamAssignment(teamAssignmentsPathMOCK)(log)(obj); @@ -110,25 +110,25 @@ describe(`Transform fns`, () => { describe(`last fn`, () => { describe(`applied to n results`, () => { it(`should pick the last one`, () => { - const nteams = `src/plugins/charts/public/static/color_maps/color_maps.ts kibana-app -src/plugins/charts/public/static/color_maps/color_maps.ts kibana-app-arch`; + const nteams = `src/plugins/charts/common/static/color_maps/color_maps.ts kibana-app +src/plugins/charts/common/static/color_maps/color_maps.ts kibana-app-arch`; const actual = last(nteams); expect(actual).toBe( - 'src/plugins/charts/public/static/color_maps/color_maps.ts kibana-app-arch' + 'src/plugins/charts/common/static/color_maps/color_maps.ts kibana-app-arch' ); }); }); describe(`applied to 1 result`, () => { it(`should pick that 1 result`, () => { const nteams = - 'src/plugins/charts/public/static/color_maps/color_maps.ts kibana-app-arch'; + 'src/plugins/charts/common/static/color_maps/color_maps.ts kibana-app-arch'; const actual = last(nteams); expect(actual).toBe( - 'src/plugins/charts/public/static/color_maps/color_maps.ts kibana-app-arch' + 'src/plugins/charts/common/static/color_maps/color_maps.ts kibana-app-arch' ); }); }); diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts index c04f0d4f9320fb..ee09c94477af41 100644 --- a/src/dev/storybook/aliases.ts +++ b/src/dev/storybook/aliases.ts @@ -25,6 +25,7 @@ export const storybookAliases = { expression_reveal_image: 'src/plugins/expression_reveal_image/.storybook', expression_shape: 'src/plugins/expression_shape/.storybook', expression_tagcloud: 'src/plugins/chart_expressions/expression_tagcloud/.storybook', + expression_metric_vis: 'src/plugins/chart_expressions/expression_metric/.storybook', fleet: 'x-pack/plugins/fleet/storybook', infra: 'x-pack/plugins/infra/.storybook', security_solution: 'x-pack/plugins/security_solution/.storybook', diff --git a/src/dev/typescript/build_ts_refs.ts b/src/dev/typescript/build_ts_refs.ts index db51ff999ccc3d..aaa8c0d12fa4da 100644 --- a/src/dev/typescript/build_ts_refs.ts +++ b/src/dev/typescript/build_ts_refs.ts @@ -11,17 +11,20 @@ import Path from 'path'; import { ToolingLog, REPO_ROOT, ProcRunner } from '@kbn/dev-utils'; import { ROOT_REFS_CONFIG_PATH } from './root_refs_config'; +import { Project } from './project'; -export async function buildAllTsRefs({ +export async function buildTsRefs({ log, procRunner, verbose, + project, }: { log: ToolingLog; procRunner: ProcRunner; verbose?: boolean; + project?: Project; }): Promise<{ failed: boolean }> { - const relative = Path.relative(REPO_ROOT, ROOT_REFS_CONFIG_PATH); + const relative = Path.relative(REPO_ROOT, project ? project.tsConfigPath : ROOT_REFS_CONFIG_PATH); log.info(`Building TypeScript projects refs for ${relative}...`); try { diff --git a/src/dev/typescript/build_ts_refs_cli.ts b/src/dev/typescript/build_ts_refs_cli.ts index a1f1d1ac7028be..c68424c2a98f7b 100644 --- a/src/dev/typescript/build_ts_refs_cli.ts +++ b/src/dev/typescript/build_ts_refs_cli.ts @@ -8,11 +8,11 @@ import Path from 'path'; -import { run, REPO_ROOT } from '@kbn/dev-utils'; +import { run, REPO_ROOT, createFlagError } from '@kbn/dev-utils'; import del from 'del'; import { RefOutputCache } from './ref_output_cache'; -import { buildAllTsRefs } from './build_ts_refs'; +import { buildTsRefs } from './build_ts_refs'; import { updateRootRefsConfig, ROOT_REFS_CONFIG_PATH } from './root_refs_config'; import { Project } from './project'; import { PROJECT_CACHE } from './projects'; @@ -41,25 +41,35 @@ export async function runBuildRefsCli() { return; } + const projectFilter = flags.project; + if (projectFilter && typeof projectFilter !== 'string') { + throw createFlagError('expected --project to be a string'); + } + // if the tsconfig.refs.json file is not self-managed then make sure it has // a reference to every composite project in the repo await updateRootRefsConfig(log); - // load all the projects referenced from the root refs config deeply, so we know all - // the ts projects we are going to be cleaning or populating with caches - const projects = Project.load( - ROOT_REFS_CONFIG_PATH, + const rootProject = Project.load( + projectFilter ? projectFilter : ROOT_REFS_CONFIG_PATH, {}, { skipConfigValidation: true, } - ).getProjectsDeep(PROJECT_CACHE); + ); + // load all the projects referenced from the root project deeply, so we know all + // the ts projects we are going to be cleaning or populating with caches + const projects = rootProject.getProjectsDeep(PROJECT_CACHE); const cacheEnabled = process.env.BUILD_TS_REFS_CACHE_ENABLE !== 'false' && !!flags.cache; const doCapture = process.env.BUILD_TS_REFS_CACHE_CAPTURE === 'true'; const doClean = !!flags.clean || doCapture; const doInitCache = cacheEnabled && !doCapture; + if (doCapture && projectFilter) { + throw createFlagError('--project can not be combined with cache capture'); + } + statsMeta.set('buildTsRefsEnabled', enabled); statsMeta.set('buildTsRefsCacheEnabled', cacheEnabled); statsMeta.set('buildTsRefsDoCapture', doCapture); @@ -87,7 +97,12 @@ export async function runBuildRefsCli() { } try { - await buildAllTsRefs({ log, procRunner, verbose: !!flags.verbose }); + await buildTsRefs({ + log, + procRunner, + verbose: !!flags.verbose, + project: rootProject, + }); log.success('ts refs build successfully'); } catch (error) { const typeFailure = isTypeFailure(error); @@ -110,13 +125,15 @@ export async function runBuildRefsCli() { } }, { - description: 'Build TypeScript projects', + description: 'Build TypeScript project references', flags: { boolean: ['clean', 'force', 'cache', 'ignore-type-failures'], + string: ['project'], default: { cache: true, }, help: ` + --project Only build the TS Refs for a specific project --force Run the build even if the BUILD_TS_REFS_DISABLE is set to "true" --clean Delete outDirs for each ts project before building --no-cache Disable fetching/extracting outDir caches based on the mergeBase with upstream diff --git a/src/dev/typescript/run_type_check_cli.ts b/src/dev/typescript/run_type_check_cli.ts index 6a286313228572..472b9c04757ca0 100644 --- a/src/dev/typescript/run_type_check_cli.ts +++ b/src/dev/typescript/run_type_check_cli.ts @@ -16,7 +16,7 @@ import { run, createFailError } from '@kbn/dev-utils'; import { lastValueFrom } from '@kbn/std'; import { PROJECTS } from './projects'; -import { buildAllTsRefs } from './build_ts_refs'; +import { buildTsRefs } from './build_ts_refs'; import { updateRootRefsConfig } from './root_refs_config'; export async function runTypeCheckCli() { @@ -26,11 +26,6 @@ export async function runTypeCheckCli() { // a reference to every composite project in the repo await updateRootRefsConfig(log); - const { failed } = await buildAllTsRefs({ log, procRunner, verbose: !!flags.verbose }); - if (failed) { - throw createFailError('Unable to build TS project refs'); - } - const projectFilter = flags.project && typeof flags.project === 'string' ? Path.resolve(flags.project) @@ -40,6 +35,16 @@ export async function runTypeCheckCli() { return !p.disableTypeCheck && (!projectFilter || p.tsConfigPath === projectFilter); }); + const { failed } = await buildTsRefs({ + log, + procRunner, + verbose: !!flags.verbose, + project: projects.length === 1 ? projects[0] : undefined, + }); + if (failed) { + throw createFailError('Unable to build TS project refs'); + } + if (!projects.length) { if (projectFilter) { throw createFailError(`Unable to find project at ${flags.project}`); diff --git a/src/plugins/chart_expressions/expression_metric/.i18nrc.json b/src/plugins/chart_expressions/expression_metric/.i18nrc.json new file mode 100755 index 00000000000000..a107bad97f2789 --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/.i18nrc.json @@ -0,0 +1,6 @@ +{ + "prefix": "expressionMetricVis", + "paths": { + "expressionMetricVis": "." + } +} diff --git a/src/plugins/chart_expressions/expression_metric/.storybook/main.js b/src/plugins/chart_expressions/expression_metric/.storybook/main.js new file mode 100644 index 00000000000000..cb483d5394285f --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/.storybook/main.js @@ -0,0 +1,23 @@ +/* + * 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 { defaultConfig } from '@kbn/storybook'; +import webpackMerge from 'webpack-merge'; +import { resolve } from 'path'; + +const mockConfig = { + resolve: { + alias: { + '../format_service': resolve(__dirname, '../public/__mocks__/format_service.ts'), + }, + }, +}; + +module.exports = { + ...defaultConfig, + webpackFinal: (config) => webpackMerge(config, mockConfig), +}; diff --git a/src/plugins/chart_expressions/expression_metric/README.md b/src/plugins/chart_expressions/expression_metric/README.md new file mode 100755 index 00000000000000..ec2541ebf74d82 --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/README.md @@ -0,0 +1,9 @@ +# expressionMetricVis + +Expression MetricVis plugin adds a `metric` renderer and function to the expression plugin. The renderer will display the `metric` chart. + +--- + +## Development + +See the [kibana contributing guide](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md) for instructions setting up your development environment. diff --git a/src/plugins/security_oss/common/index.ts b/src/plugins/chart_expressions/expression_metric/common/constants.ts similarity index 87% rename from src/plugins/security_oss/common/index.ts rename to src/plugins/chart_expressions/expression_metric/common/constants.ts index f02bc941d19e26..b39902f61ac459 100644 --- a/src/plugins/security_oss/common/index.ts +++ b/src/plugins/chart_expressions/expression_metric/common/constants.ts @@ -6,4 +6,4 @@ * Side Public License, v 1. */ -export type { AppState } from './app_state'; +export const EXPRESSION_METRIC_NAME = 'metricVis'; diff --git a/src/plugins/vis_types/metric/public/__snapshots__/metric_vis_fn.test.ts.snap b/src/plugins/chart_expressions/expression_metric/common/expression_functions/__snapshots__/metric_vis_function.test.ts.snap similarity index 98% rename from src/plugins/vis_types/metric/public/__snapshots__/metric_vis_fn.test.ts.snap rename to src/plugins/chart_expressions/expression_metric/common/expression_functions/__snapshots__/metric_vis_function.test.ts.snap index a3be4d10d9bfd2..03055764cc4a47 100644 --- a/src/plugins/vis_types/metric/public/__snapshots__/metric_vis_fn.test.ts.snap +++ b/src/plugins/chart_expressions/expression_metric/common/expression_functions/__snapshots__/metric_vis_function.test.ts.snap @@ -22,7 +22,7 @@ Object { exports[`interpreter/functions#metric returns an object with the correct structure 1`] = ` Object { - "as": "metric_vis", + "as": "metricVis", "type": "render", "value": Object { "visConfig": Object { diff --git a/src/plugins/security_oss/public/insecure_cluster_service/components/index.ts b/src/plugins/chart_expressions/expression_metric/common/expression_functions/index.ts similarity index 83% rename from src/plugins/security_oss/public/insecure_cluster_service/components/index.ts rename to src/plugins/chart_expressions/expression_metric/common/expression_functions/index.ts index 8405fa3d436819..5eccaa62fe4645 100644 --- a/src/plugins/security_oss/public/insecure_cluster_service/components/index.ts +++ b/src/plugins/chart_expressions/expression_metric/common/expression_functions/index.ts @@ -6,4 +6,4 @@ * Side Public License, v 1. */ -export { defaultAlertTitle, defaultAlertText } from './default_alert'; +export { metricVisFunction } from './metric_vis_function'; diff --git a/src/plugins/vis_types/metric/public/metric_vis_fn.test.ts b/src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.test.ts similarity index 81% rename from src/plugins/vis_types/metric/public/metric_vis_fn.test.ts rename to src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.test.ts index 28124a653629c0..1f90322e703b8c 100644 --- a/src/plugins/vis_types/metric/public/metric_vis_fn.test.ts +++ b/src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.test.ts @@ -6,14 +6,13 @@ * Side Public License, v 1. */ -import { createMetricVisFn } from './metric_vis_fn'; -import { functionWrapper } from '../../../expressions/common/expression_functions/specs/tests/utils'; -import { Datatable } from '../../../expressions/common/expression_types/specs'; - -type Arguments = Parameters['fn']>[1]; +import { metricVisFunction } from './metric_vis_function'; +import type { MetricArguments } from '../../common'; +import { functionWrapper } from '../../../../expressions/common/expression_functions/specs/tests/utils'; +import { Datatable } from '../../../../expressions/common/expression_types/specs'; describe('interpreter/functions#metric', () => { - const fn = functionWrapper(createMetricVisFn()); + const fn = functionWrapper(metricVisFunction()); const context = { type: 'datatable', rows: [{ 'col-0-1': 0 }], @@ -52,7 +51,7 @@ describe('interpreter/functions#metric', () => { aggType: 'count', }, ], - } as unknown as Arguments; + } as unknown as MetricArguments; it('returns an object with the correct structure', () => { const actual = fn(context, args, undefined); diff --git a/src/plugins/vis_types/metric/public/metric_vis_fn.ts b/src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.ts similarity index 66% rename from src/plugins/vis_types/metric/public/metric_vis_fn.ts rename to src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.ts index 210552732bc0a4..31f5b8421b3a6e 100644 --- a/src/plugins/vis_types/metric/public/metric_vis_fn.ts +++ b/src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.ts @@ -8,60 +8,24 @@ import { i18n } from '@kbn/i18n'; -import { - ExpressionFunctionDefinition, - Datatable, - Range, - Render, - Style, -} from '../../../expressions/public'; -import { visType, VisParams } from './types'; -import { prepareLogTable, Dimension } from '../../../visualizations/public'; -import { ColorSchemas, vislibColorMaps, ColorMode } from '../../../charts/public'; -import { ExpressionValueVisDimension } from '../../../visualizations/public'; +import { visType } from '../types'; +import { prepareLogTable, Dimension } from '../../../../visualizations/common/prepare_log_table'; +import { vislibColorMaps, ColorMode } from '../../../../charts/common'; +import { MetricVisExpressionFunctionDefinition } from '../types'; +import { EXPRESSION_METRIC_NAME } from '../constants'; -export type Input = Datatable; - -interface Arguments { - percentageMode: boolean; - colorSchema: ColorSchemas; - colorMode: ColorMode; - useRanges: boolean; - invertColors: boolean; - showLabels: boolean; - bgFill: string; - subText: string; - colorRange: Range[]; - font: Style; - metric: ExpressionValueVisDimension[]; - bucket: ExpressionValueVisDimension; -} - -export interface MetricVisRenderValue { - visType: typeof visType; - visData: Input; - visConfig: Pick; -} - -export type MetricVisExpressionFunctionDefinition = ExpressionFunctionDefinition< - 'metricVis', - Input, - Arguments, - Render ->; - -export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ - name: 'metricVis', +export const metricVisFunction = (): MetricVisExpressionFunctionDefinition => ({ + name: EXPRESSION_METRIC_NAME, type: 'render', inputTypes: ['datatable'], - help: i18n.translate('visTypeMetric.function.help', { + help: i18n.translate('expressionMetricVis.function.help', { defaultMessage: 'Metric visualization', }), args: { percentageMode: { types: ['boolean'], default: false, - help: i18n.translate('visTypeMetric.function.percentageMode.help', { + help: i18n.translate('expressionMetricVis.function.percentageMode.help', { defaultMessage: 'Shows metric in percentage mode. Requires colorRange to be set.', }), }, @@ -69,7 +33,7 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ types: ['string'], default: '"Green to Red"', options: Object.values(vislibColorMaps).map((value: any) => value.id), - help: i18n.translate('visTypeMetric.function.colorSchema.help', { + help: i18n.translate('expressionMetricVis.function.colorSchema.help', { defaultMessage: 'Color schema to use', }), }, @@ -77,7 +41,7 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ types: ['string'], default: '"None"', options: [ColorMode.None, ColorMode.Labels, ColorMode.Background], - help: i18n.translate('visTypeMetric.function.colorMode.help', { + help: i18n.translate('expressionMetricVis.function.colorMode.help', { defaultMessage: 'Which part of metric to color', }), }, @@ -85,7 +49,7 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ types: ['range'], multi: true, default: '{range from=0 to=10000}', - help: i18n.translate('visTypeMetric.function.colorRange.help', { + help: i18n.translate('expressionMetricVis.function.colorRange.help', { defaultMessage: 'A range object specifying groups of values to which different colors should be applied.', }), @@ -93,21 +57,21 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ useRanges: { types: ['boolean'], default: false, - help: i18n.translate('visTypeMetric.function.useRanges.help', { + help: i18n.translate('expressionMetricVis.function.useRanges.help', { defaultMessage: 'Enabled color ranges.', }), }, invertColors: { types: ['boolean'], default: false, - help: i18n.translate('visTypeMetric.function.invertColors.help', { + help: i18n.translate('expressionMetricVis.function.invertColors.help', { defaultMessage: 'Inverts the color ranges', }), }, showLabels: { types: ['boolean'], default: true, - help: i18n.translate('visTypeMetric.function.showLabels.help', { + help: i18n.translate('expressionMetricVis.function.showLabels.help', { defaultMessage: 'Shows labels under the metric values.', }), }, @@ -115,14 +79,14 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ types: ['string'], default: '"#000"', aliases: ['backgroundFill', 'bgColor', 'backgroundColor'], - help: i18n.translate('visTypeMetric.function.bgFill.help', { + help: i18n.translate('expressionMetricVis.function.bgFill.help', { defaultMessage: 'Color as html hex code (#123456), html color (red, blue) or rgba value (rgba(255,255,255,1)).', }), }, font: { types: ['style'], - help: i18n.translate('visTypeMetric.function.font.help', { + help: i18n.translate('expressionMetricVis.function.font.help', { defaultMessage: 'Font settings.', }), default: '{font size=60}', @@ -131,13 +95,13 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ types: ['string'], aliases: ['label', 'text', 'description'], default: '""', - help: i18n.translate('visTypeMetric.function.subText.help', { + help: i18n.translate('expressionMetricVis.function.subText.help', { defaultMessage: 'Custom text to show under the metric', }), }, metric: { types: ['vis_dimension'], - help: i18n.translate('visTypeMetric.function.metric.help', { + help: i18n.translate('expressionMetricVis.function.metric.help', { defaultMessage: 'metric dimension configuration', }), required: true, @@ -145,7 +109,7 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ }, bucket: { types: ['vis_dimension'], - help: i18n.translate('visTypeMetric.function.bucket.help', { + help: i18n.translate('expressionMetricVis.function.bucket.help', { defaultMessage: 'bucket dimension configuration', }), }, @@ -161,7 +125,7 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ const argsTable: Dimension[] = [ [ args.metric, - i18n.translate('visTypeMetric.function.dimension.metric', { + i18n.translate('expressionMetricVis.function.dimension.metric', { defaultMessage: 'Metric', }), ], @@ -169,7 +133,7 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ if (args.bucket) { argsTable.push([ [args.bucket], - i18n.translate('visTypeMetric.function.adimension.splitGroup', { + i18n.translate('expressionMetricVis.function.dimension.splitGroup', { defaultMessage: 'Split group', }), ]); @@ -180,7 +144,7 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ return { type: 'render', - as: 'metric_vis', + as: EXPRESSION_METRIC_NAME, value: { visData: input, visType, diff --git a/src/plugins/chart_expressions/expression_metric/common/index.ts b/src/plugins/chart_expressions/expression_metric/common/index.ts new file mode 100755 index 00000000000000..ee023dca2f4ffa --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/common/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. + */ + +export const PLUGIN_ID = 'expressionMetricVis'; +export const PLUGIN_NAME = 'expressionMetricVis'; + +export type { + MetricArguments, + MetricInput, + MetricVisRenderConfig, + MetricVisExpressionFunctionDefinition, + DimensionsVisParam, + MetricVisParam, + VisParams, + MetricOptions, +} from './types'; + +export { metricVisFunction } from './expression_functions'; + +export { EXPRESSION_METRIC_NAME } from './constants'; diff --git a/src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts new file mode 100644 index 00000000000000..5e8b01ec930054 --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts @@ -0,0 +1,49 @@ +/* + * 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 { + Datatable, + ExpressionFunctionDefinition, + Range, + ExpressionValueRender, + Style, +} from '../../../../expressions'; +import { ExpressionValueVisDimension } from '../../../../visualizations/common'; +import { ColorSchemas, ColorMode } from '../../../../charts/common'; +import { VisParams, visType } from './expression_renderers'; +import { EXPRESSION_METRIC_NAME } from '../constants'; + +export interface MetricArguments { + percentageMode: boolean; + colorSchema: ColorSchemas; + colorMode: ColorMode; + useRanges: boolean; + invertColors: boolean; + showLabels: boolean; + bgFill: string; + subText: string; + colorRange: Range[]; + font: Style; + metric: ExpressionValueVisDimension[]; + bucket: ExpressionValueVisDimension; +} + +export type MetricInput = Datatable; + +export interface MetricVisRenderConfig { + visType: typeof visType; + visData: MetricInput; + visConfig: Pick; +} + +export type MetricVisExpressionFunctionDefinition = ExpressionFunctionDefinition< + typeof EXPRESSION_METRIC_NAME, + MetricInput, + MetricArguments, + ExpressionValueRender +>; diff --git a/src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts b/src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts new file mode 100644 index 00000000000000..2cc7ce853f8bf3 --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/common/types/expression_renderers.ts @@ -0,0 +1,46 @@ +/* + * 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 { Range } from '../../../../expressions/common'; +import { ExpressionValueVisDimension } from '../../../../visualizations/common'; +import { ColorMode, Labels, Style, ColorSchemas } from '../../../../charts/common'; + +export const visType = 'metric'; + +export interface DimensionsVisParam { + metrics: ExpressionValueVisDimension[]; + bucket?: ExpressionValueVisDimension; +} + +export interface MetricVisParam { + percentageMode: boolean; + percentageFormatPattern?: string; + useRanges: boolean; + colorSchema: ColorSchemas; + metricColorMode: ColorMode; + colorsRange: Range[]; + labels: Labels; + invertColors: boolean; + style: Style; +} + +export interface VisParams { + addTooltip: boolean; + addLegend: boolean; + dimensions: DimensionsVisParam; + metric: MetricVisParam; + type: typeof visType; +} + +export interface MetricOptions { + value: string; + label: string; + color?: string; + bgColor?: string; + lightText: boolean; + rowIndex: number; +} diff --git a/src/plugins/chart_expressions/expression_metric/common/types/index.ts b/src/plugins/chart_expressions/expression_metric/common/types/index.ts new file mode 100644 index 00000000000000..9c50bfab1305d3 --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/common/types/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './expression_functions'; +export * from './expression_renderers'; diff --git a/src/plugins/security_oss/jest.config.js b/src/plugins/chart_expressions/expression_metric/jest.config.js similarity index 55% rename from src/plugins/security_oss/jest.config.js rename to src/plugins/chart_expressions/expression_metric/jest.config.js index 692d85f69a7405..d737b45f34e69d 100644 --- a/src/plugins/security_oss/jest.config.js +++ b/src/plugins/chart_expressions/expression_metric/jest.config.js @@ -8,9 +8,12 @@ module.exports = { preset: '@kbn/test', - rootDir: '../../..', - roots: ['/src/plugins/security_oss'], - coverageDirectory: '/target/kibana-coverage/jest/src/plugins/security_oss', + rootDir: '../../../../', + roots: ['/src/plugins/chart_expressions/expression_metric'], + coverageDirectory: + '/target/kibana-coverage/jest/src/plugins/chart_expressions/expression_metric', coverageReporters: ['text', 'html'], - collectCoverageFrom: ['/src/plugins/security_oss/{common,public,server}/**/*.{ts,tsx}'], + collectCoverageFrom: [ + '/src/plugins/chart_expressions/expression_metric/{common,public,server}/**/*.{ts,tsx}', + ], }; diff --git a/src/plugins/chart_expressions/expression_metric/kibana.json b/src/plugins/chart_expressions/expression_metric/kibana.json new file mode 100755 index 00000000000000..c662dc13103233 --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/kibana.json @@ -0,0 +1,15 @@ +{ + "id": "expressionMetricVis", + "version": "1.0.0", + "kibanaVersion": "kibana", + "owner": { + "name": "Vis Editors", + "githubTeam": "kibana-vis-editors" + }, + "description": "Expression MetricVis plugin adds a `metric` renderer and function to the expression plugin. The renderer will display the `metric` chart.", + "server": true, + "ui": true, + "requiredPlugins": ["expressions", "fieldFormats", "charts", "visualizations", "presentationUtil"], + "requiredBundles": ["kibanaUtils"], + "optionalPlugins": [] +} diff --git a/src/plugins/chart_expressions/expression_metric/public/__mocks__/format_service.ts b/src/plugins/chart_expressions/expression_metric/public/__mocks__/format_service.ts new file mode 100644 index 00000000000000..77f6d8eb0bf376 --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/public/__mocks__/format_service.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. + */ + +export const getFormatService = () => ({ + deserialize: (target: any) => ({ + convert: (text: string, format: string) => text, + }), +}); diff --git a/src/plugins/chart_expressions/expression_metric/public/__stories__/metric_renderer.stories.tsx b/src/plugins/chart_expressions/expression_metric/public/__stories__/metric_renderer.stories.tsx new file mode 100644 index 00000000000000..b22616af01c913 --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/public/__stories__/metric_renderer.stories.tsx @@ -0,0 +1,250 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import { ExpressionValueVisDimension } from '../../../../visualizations/common'; +import { DatatableColumn, Range } from '../../../../expressions'; +import { Render } from '../../../../presentation_util/public/__stories__'; +import { ColorMode, ColorSchemas } from '../../../../charts/common'; +import { metricVisRenderer } from '../expression_renderers'; +import { MetricVisRenderConfig, visType } from '../../common/types'; + +const config: MetricVisRenderConfig = { + visType, + visData: { + type: 'datatable', + rows: [{ 'col-0-1': 85, 'col-0-2': 30 }], + columns: [ + { + id: 'col-0-1', + name: 'Max products count', + meta: { type: 'number', params: {} }, + }, + { + id: 'col-0-2', + name: 'Median products count', + meta: { type: 'number', params: {} }, + }, + ], + }, + visConfig: { + metric: { + percentageMode: false, + useRanges: false, + colorSchema: ColorSchemas.GreenToRed, + metricColorMode: ColorMode.None, + colorsRange: [], + labels: { show: true }, + invertColors: false, + style: { + bgColor: false, + bgFill: '#000', + fontSize: 60, + labelColor: false, + subText: '', + }, + }, + dimensions: { + metrics: [ + { + accessor: 0, + format: { + id: 'number', + params: {}, + }, + type: 'vis_dimension', + }, + { + accessor: { + id: 'col-0-2', + name: 'Median products count', + meta: { type: 'number' }, + }, + format: { + id: 'number', + params: {}, + }, + type: 'vis_dimension', + }, + ], + }, + }, +}; + +const dayColumn: DatatableColumn = { + id: 'col-0-3', + name: 'Day of the week', + meta: { type: 'string', params: {} }, +}; + +const dayAccessor: ExpressionValueVisDimension = { + accessor: { + id: 'col-0-3', + name: 'Day of the week', + meta: { type: 'string' }, + }, + format: { + id: 'string', + params: {}, + }, + type: 'vis_dimension', +}; + +const dataWithBuckets = [ + { 'col-0-1': 85, 'col-0-2': 30, 'col-0-3': 'Monday' }, + { 'col-0-1': 55, 'col-0-2': 32, 'col-0-3': 'Tuesday' }, + { 'col-0-1': 56, 'col-0-2': 52, 'col-0-3': 'Wednesday' }, +]; + +const colorsRange: Range[] = [ + { type: 'range', from: 0, to: 50 }, + { type: 'range', from: 51, to: 150 }, +]; + +const containerSize = { + width: '700px', + height: '700px', +}; + +storiesOf('renderers/visMetric', module) + .add('Default', () => { + return ; + }) + .add('Without labels', () => { + return ( + + ); + }) + .add('With custom font size', () => { + return ( + + ); + }) + .add('With color ranges, background color mode', () => { + return ( + + ); + }) + .add('With color ranges, labels color mode', () => { + return ( + + ); + }) + .add('With color ranges, labels color mode, reverse mode', () => { + return ( + + ); + }) + .add('With bucket', () => { + return ( + + ); + }) + .add('With empty results', () => { + return ( + + ); + }); diff --git a/src/plugins/vis_types/metric/public/components/__snapshots__/metric_vis_component.test.tsx.snap b/src/plugins/chart_expressions/expression_metric/public/components/__snapshots__/metric_component.test.tsx.snap similarity index 100% rename from src/plugins/vis_types/metric/public/components/__snapshots__/metric_vis_component.test.tsx.snap rename to src/plugins/chart_expressions/expression_metric/public/components/__snapshots__/metric_component.test.tsx.snap diff --git a/src/plugins/vis_types/metric/public/components/metric_vis.scss b/src/plugins/chart_expressions/expression_metric/public/components/metric.scss similarity index 100% rename from src/plugins/vis_types/metric/public/components/metric_vis.scss rename to src/plugins/chart_expressions/expression_metric/public/components/metric.scss diff --git a/src/plugins/vis_types/metric/public/components/metric_vis_component.test.tsx b/src/plugins/chart_expressions/expression_metric/public/components/metric_component.test.tsx similarity index 97% rename from src/plugins/vis_types/metric/public/components/metric_vis_component.test.tsx rename to src/plugins/chart_expressions/expression_metric/public/components/metric_component.test.tsx index c66704c44ea0db..ec3b9aee8583c3 100644 --- a/src/plugins/vis_types/metric/public/components/metric_vis_component.test.tsx +++ b/src/plugins/chart_expressions/expression_metric/public/components/metric_component.test.tsx @@ -9,9 +9,9 @@ import React from 'react'; import { shallow } from 'enzyme'; -import MetricVisComponent, { MetricVisComponentProps } from './metric_vis_component'; +import MetricVisComponent, { MetricVisComponentProps } from './metric_component'; -jest.mock('../services', () => ({ +jest.mock('../format_service', () => ({ getFormatService: () => ({ deserialize: () => { return { diff --git a/src/plugins/vis_types/metric/public/components/metric_vis_component.tsx b/src/plugins/chart_expressions/expression_metric/public/components/metric_component.tsx similarity index 81% rename from src/plugins/vis_types/metric/public/components/metric_vis_component.tsx rename to src/plugins/chart_expressions/expression_metric/public/components/metric_component.tsx index 837ec5ff60dc55..4efdefc7d28ee2 100644 --- a/src/plugins/vis_types/metric/public/components/metric_vis_component.tsx +++ b/src/plugins/chart_expressions/expression_metric/public/components/metric_component.tsx @@ -9,21 +9,19 @@ import { last, findIndex, isNaN } from 'lodash'; import React, { Component } from 'react'; import { isColorDark } from '@elastic/eui'; -import { MetricVisValue } from './metric_vis_value'; -import { Input } from '../metric_vis_fn'; +import { MetricVisValue } from './metric_value'; +import { MetricInput, VisParams, MetricOptions } from '../../common/types'; import type { FieldFormatsContentType, IFieldFormat } from '../../../../field_formats/common'; import { Datatable } from '../../../../expressions/public'; import { getHeatmapColors } from '../../../../charts/public'; -import { VisParams, MetricVisMetric } from '../types'; -import { getFormatService } from '../services'; +import { getFormatService } from '../format_service'; import { ExpressionValueVisDimension } from '../../../../visualizations/public'; -import { Range } from '../../../../expressions/public'; -import './metric_vis.scss'; +import './metric.scss'; export interface MetricVisComponentProps { visParams: Pick; - visData: Input; + visData: MetricInput; fireEvent: (event: any) => void; renderComplete: () => void; } @@ -33,7 +31,7 @@ class MetricVisComponent extends Component { const config = this.props.visParams.metric; const isPercentageMode = config.percentageMode; const colorsRange = config.colorsRange; - const max = (last(colorsRange) as Range).to; + const max = last(colorsRange)?.to ?? 1; const labels: string[] = []; colorsRange.forEach((range: any) => { @@ -66,7 +64,7 @@ class MetricVisComponent extends Component { }); if (bucket === -1) { - if (val < config.colorsRange[0].from) bucket = 0; + if (config.colorsRange?.[0] && val < config.colorsRange?.[0].from) bucket = 0; else bucket = config.colorsRange.length - 1; } @@ -109,14 +107,13 @@ class MetricVisComponent extends Component { } private processTableGroups(table: Datatable) { - const config = this.props.visParams.metric; - const dimensions = this.props.visParams.dimensions; - const isPercentageMode = config.percentageMode; - const min = config.colorsRange[0].from; - const max = (last(config.colorsRange) as Range).to; + const { metric: metricConfig, dimensions } = this.props.visParams; + const { percentageMode: isPercentageMode, colorsRange, style } = metricConfig; + const min = colorsRange?.[0]?.from; + const max = last(colorsRange)?.to; const colors = this.getColors(); const labels = this.getLabels(); - const metrics: MetricVisMetric[] = []; + const metrics: MetricOptions[] = []; let bucketColumnId: string; let bucketFormatter: IFieldFormat; @@ -131,27 +128,26 @@ class MetricVisComponent extends Component { const formatter = getFormatService().deserialize(metric.format); table.rows.forEach((row, rowIndex) => { let title = column.name; - let value: any = row[column.id]; + let value: number = row[column.id]; const color = this.getColor(value, labels, colors); - if (isPercentageMode) { + if (isPercentageMode && colorsRange?.length && max !== undefined && min !== undefined) { value = (value - min) / (max - min); } - value = this.getFormattedValue(formatter, value, 'html'); - + const formattedValue = this.getFormattedValue(formatter, value, 'html'); if (bucketColumnId) { const bucketValue = this.getFormattedValue(bucketFormatter, row[bucketColumnId]); title = `${bucketValue} - ${title}`; } - const shouldColor = config.colorsRange.length > 1; + const shouldColor = colorsRange && colorsRange.length > 1; metrics.push({ label: title, - value, - color: shouldColor && config.style.labelColor ? color : undefined, - bgColor: shouldColor && config.style.bgColor ? color : undefined, - lightText: shouldColor && config.style.bgColor && this.needsLightText(color), + value: formattedValue, + color: shouldColor && style.labelColor ? color : undefined, + bgColor: shouldColor && style.bgColor ? color : undefined, + lightText: shouldColor && style.bgColor && this.needsLightText(color), rowIndex, }); }); @@ -160,7 +156,7 @@ class MetricVisComponent extends Component { return metrics; } - private filterBucket = (metric: MetricVisMetric) => { + private filterBucket = (metric: MetricOptions) => { const dimensions = this.props.visParams.dimensions; if (!dimensions.bucket) { return; @@ -180,7 +176,7 @@ class MetricVisComponent extends Component { }); }; - private renderMetric = (metric: MetricVisMetric, index: number) => { + private renderMetric = (metric: MetricOptions, index: number) => { return ( void; + onFilter?: (metric: MetricOptions) => void; showLabel?: boolean; } diff --git a/src/plugins/security_oss/public/config.ts b/src/plugins/chart_expressions/expression_metric/public/expression_renderers/index.ts similarity index 83% rename from src/plugins/security_oss/public/config.ts rename to src/plugins/chart_expressions/expression_metric/public/expression_renderers/index.ts index 7b0e201bd56585..b4fb6cea84aa35 100644 --- a/src/plugins/security_oss/public/config.ts +++ b/src/plugins/chart_expressions/expression_metric/public/expression_renderers/index.ts @@ -6,6 +6,4 @@ * Side Public License, v 1. */ -export interface ConfigType { - showInsecureClusterWarning: boolean; -} +export { metricVisRenderer } from './metric_vis_renderer'; diff --git a/src/plugins/vis_types/metric/public/metric_vis_renderer.tsx b/src/plugins/chart_expressions/expression_metric/public/expression_renderers/metric_vis_renderer.tsx similarity index 73% rename from src/plugins/vis_types/metric/public/metric_vis_renderer.tsx rename to src/plugins/chart_expressions/expression_metric/public/expression_renderers/metric_vis_renderer.tsx index 0bd2efbfe2efbe..6c3c7696fca402 100644 --- a/src/plugins/vis_types/metric/public/metric_vis_renderer.tsx +++ b/src/plugins/chart_expressions/expression_metric/public/expression_renderers/metric_vis_renderer.tsx @@ -9,14 +9,15 @@ import React, { lazy } from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import { VisualizationContainer } from '../../../visualizations/public'; -import { ExpressionRenderDefinition } from '../../../expressions/common/expression_renderers'; -import { MetricVisRenderValue } from './metric_vis_fn'; +import { VisualizationContainer } from '../../../../visualizations/public'; +import { ExpressionRenderDefinition } from '../../../../expressions/common/expression_renderers'; +import { EXPRESSION_METRIC_NAME, MetricVisRenderConfig } from '../../common'; + // @ts-ignore -const MetricVisComponent = lazy(() => import('./components/metric_vis_component')); +const MetricVisComponent = lazy(() => import('../components/metric_component')); -export const metricVisRenderer: () => ExpressionRenderDefinition = () => ({ - name: 'metric_vis', +export const metricVisRenderer: () => ExpressionRenderDefinition = () => ({ + name: EXPRESSION_METRIC_NAME, displayName: 'metric visualization', reuseDomNode: true, render: async (domNode, { visData, visConfig }, handlers) => { diff --git a/src/plugins/security_oss/common/app_state.ts b/src/plugins/chart_expressions/expression_metric/public/format_service.ts similarity index 59% rename from src/plugins/security_oss/common/app_state.ts rename to src/plugins/chart_expressions/expression_metric/public/format_service.ts index c6ccbb17377a3e..19d2f9a5568ce5 100644 --- a/src/plugins/security_oss/common/app_state.ts +++ b/src/plugins/chart_expressions/expression_metric/public/format_service.ts @@ -6,13 +6,8 @@ * Side Public License, v 1. */ -/** - * Defines Security OSS application state. - */ -export interface AppState { - insecureClusterAlert: { displayAlert: boolean }; - anonymousAccess: { - isEnabled: boolean; - accessURLParameters: Record | null; - }; -} +import { createGetterSetter } from '../../../kibana_utils/public'; +import { FieldFormatsStart } from '../../../field_formats/public'; + +export const [getFormatService, setFormatService] = + createGetterSetter('fieldFormats'); diff --git a/src/plugins/chart_expressions/expression_metric/public/index.ts b/src/plugins/chart_expressions/expression_metric/public/index.ts new file mode 100644 index 00000000000000..dfb442514d5f0b --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/public/index.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 { ExpressionMetricPlugin } from './plugin'; + +export function plugin() { + return new ExpressionMetricPlugin(); +} diff --git a/src/plugins/chart_expressions/expression_metric/public/plugin.ts b/src/plugins/chart_expressions/expression_metric/public/plugin.ts new file mode 100644 index 00000000000000..3ac338380a3981 --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/public/plugin.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 { CoreSetup, CoreStart, Plugin } from '../../../../core/public'; +import { Plugin as ExpressionsPublicPlugin } from '../../../expressions/public'; +import { metricVisFunction } from '../common'; +import { setFormatService } from './format_service'; +import { metricVisRenderer } from './expression_renderers'; +import { FieldFormatsStart } from '../../../field_formats/public'; + +/** @internal */ +export interface ExpressionMetricPluginSetup { + expressions: ReturnType; +} + +/** @internal */ +export interface ExpressionMetricPluginStart { + fieldFormats: FieldFormatsStart; +} + +/** @internal */ +export class ExpressionMetricPlugin implements Plugin { + public setup(core: CoreSetup, { expressions }: ExpressionMetricPluginSetup) { + expressions.registerFunction(metricVisFunction); + expressions.registerRenderer(metricVisRenderer); + } + + public start(core: CoreStart, { fieldFormats }: ExpressionMetricPluginStart) { + setFormatService(fieldFormats); + } +} diff --git a/src/plugins/chart_expressions/expression_metric/server/index.ts b/src/plugins/chart_expressions/expression_metric/server/index.ts new file mode 100644 index 00000000000000..dfb442514d5f0b --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/server/index.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 { ExpressionMetricPlugin } from './plugin'; + +export function plugin() { + return new ExpressionMetricPlugin(); +} diff --git a/src/plugins/chart_expressions/expression_metric/server/plugin.ts b/src/plugins/chart_expressions/expression_metric/server/plugin.ts new file mode 100644 index 00000000000000..1a04d4702361f2 --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/server/plugin.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CoreSetup, CoreStart, Plugin } from '../../../../core/public'; +import { ExpressionsServerStart, ExpressionsServerSetup } from '../../../expressions/server'; +import { metricVisFunction } from '../common'; + +interface SetupDeps { + expressions: ExpressionsServerSetup; +} + +interface StartDeps { + expression: ExpressionsServerStart; +} + +export type ExpressionMetricPluginSetup = void; +export type ExpressionMetricPluginStart = void; + +export class ExpressionMetricPlugin + implements Plugin +{ + public setup(core: CoreSetup, { expressions }: SetupDeps): ExpressionMetricPluginSetup { + expressions.registerFunction(metricVisFunction); + } + + public start(core: CoreStart): ExpressionMetricPluginStart {} + + public stop() {} +} diff --git a/src/plugins/chart_expressions/expression_metric/tsconfig.json b/src/plugins/chart_expressions/expression_metric/tsconfig.json new file mode 100644 index 00000000000000..ff5089c7f4d215 --- /dev/null +++ b/src/plugins/chart_expressions/expression_metric/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true, + "isolatedModules": true + }, + "include": [ + "common/**/*", + "public/**/*", + "server/**/*", + ], + "references": [ + { "path": "../../../core/tsconfig.json" }, + { "path": "../../expressions/tsconfig.json" }, + { "path": "../../presentation_util/tsconfig.json" }, + { "path": "../../field_formats/tsconfig.json" }, + { "path": "../../charts/tsconfig.json" }, + { "path": "../../visualizations/tsconfig.json" }, + ] +} diff --git a/src/plugins/charts/common/index.ts b/src/plugins/charts/common/index.ts index ad3d2d11bbdfda..618466212f5bb7 100644 --- a/src/plugins/charts/common/index.ts +++ b/src/plugins/charts/common/index.ts @@ -6,9 +6,33 @@ * Side Public License, v 1. */ -// TODO: https://github.com/elastic/kibana/issues/110891 -/* eslint-disable @kbn/eslint/no_export_all */ - export const COLOR_MAPPING_SETTING = 'visualization:colorMapping'; -export * from './palette'; -export * from './constants'; + +export { + CustomPaletteArguments, + CustomPaletteState, + SystemPaletteArguments, + PaletteOutput, + defaultCustomColors, + palette, + systemPalette, +} from './palette'; + +export { paletteIds } from './constants'; + +export { + ColorSchemas, + ColorSchema, + RawColorSchema, + ColorMap, + vislibColorMaps, + colorSchemas, + getHeatmapColors, + truncatedColorMaps, + truncatedColorSchemas, + ColorMode, + LabelRotation, + defaultCountLabel, +} from './static'; + +export { ColorSchemaParams, Labels, Style } from './types'; diff --git a/src/plugins/charts/public/static/color_maps/color_maps.ts b/src/plugins/charts/common/static/color_maps/color_maps.ts similarity index 100% rename from src/plugins/charts/public/static/color_maps/color_maps.ts rename to src/plugins/charts/common/static/color_maps/color_maps.ts diff --git a/src/plugins/charts/public/static/color_maps/heatmap_color.test.ts b/src/plugins/charts/common/static/color_maps/heatmap_color.test.ts similarity index 100% rename from src/plugins/charts/public/static/color_maps/heatmap_color.test.ts rename to src/plugins/charts/common/static/color_maps/heatmap_color.test.ts diff --git a/src/plugins/charts/public/static/color_maps/heatmap_color.ts b/src/plugins/charts/common/static/color_maps/heatmap_color.ts similarity index 100% rename from src/plugins/charts/public/static/color_maps/heatmap_color.ts rename to src/plugins/charts/common/static/color_maps/heatmap_color.ts diff --git a/src/plugins/charts/public/static/color_maps/index.ts b/src/plugins/charts/common/static/color_maps/index.ts similarity index 100% rename from src/plugins/charts/public/static/color_maps/index.ts rename to src/plugins/charts/common/static/color_maps/index.ts diff --git a/src/plugins/charts/public/static/color_maps/mock.ts b/src/plugins/charts/common/static/color_maps/mock.ts similarity index 100% rename from src/plugins/charts/public/static/color_maps/mock.ts rename to src/plugins/charts/common/static/color_maps/mock.ts diff --git a/src/plugins/charts/public/static/color_maps/truncated_color_maps.ts b/src/plugins/charts/common/static/color_maps/truncated_color_maps.ts similarity index 100% rename from src/plugins/charts/public/static/color_maps/truncated_color_maps.ts rename to src/plugins/charts/common/static/color_maps/truncated_color_maps.ts diff --git a/src/plugins/charts/public/static/components/collections.ts b/src/plugins/charts/common/static/components/collections.ts similarity index 100% rename from src/plugins/charts/public/static/components/collections.ts rename to src/plugins/charts/common/static/components/collections.ts diff --git a/src/plugins/security_oss/public/app_state/index.ts b/src/plugins/charts/common/static/components/index.ts similarity index 82% rename from src/plugins/security_oss/public/app_state/index.ts rename to src/plugins/charts/common/static/components/index.ts index 585dc132583014..9b2384d237714b 100644 --- a/src/plugins/security_oss/public/app_state/index.ts +++ b/src/plugins/charts/common/static/components/index.ts @@ -6,4 +6,4 @@ * Side Public License, v 1. */ -export { AppStateService, AppStateServiceStart } from './app_state_service'; +export { ColorMode, LabelRotation, defaultCountLabel } from './collections'; diff --git a/src/plugins/security_oss/public/insecure_cluster_service/index.ts b/src/plugins/charts/common/static/index.ts similarity index 58% rename from src/plugins/security_oss/public/insecure_cluster_service/index.ts rename to src/plugins/charts/common/static/index.ts index 4f087ad56d7155..9cde3bafe59e43 100644 --- a/src/plugins/security_oss/public/insecure_cluster_service/index.ts +++ b/src/plugins/charts/common/static/index.ts @@ -7,7 +7,15 @@ */ export { - InsecureClusterService, - InsecureClusterServiceSetup, - InsecureClusterServiceStart, -} from './insecure_cluster_service'; + ColorSchemas, + ColorSchema, + RawColorSchema, + ColorMap, + vislibColorMaps, + colorSchemas, + getHeatmapColors, + truncatedColorMaps, + truncatedColorSchemas, +} from './color_maps'; + +export { ColorMode, LabelRotation, defaultCountLabel } from './components'; diff --git a/src/plugins/charts/public/static/components/types.ts b/src/plugins/charts/common/types.ts similarity index 88% rename from src/plugins/charts/public/static/components/types.ts rename to src/plugins/charts/common/types.ts index a92dba593f0c7e..841494c2edb8af 100644 --- a/src/plugins/charts/public/static/components/types.ts +++ b/src/plugins/charts/common/types.ts @@ -6,8 +6,7 @@ * Side Public License, v 1. */ -import { ColorSchemas } from '../color_maps'; -import { LabelRotation } from './collections'; +import { ColorSchemas, LabelRotation } from './static'; export interface ColorSchemaParams { colorSchema: ColorSchemas; diff --git a/src/plugins/charts/kibana.json b/src/plugins/charts/kibana.json index 86971d1018e0e8..a3e0da41056d77 100644 --- a/src/plugins/charts/kibana.json +++ b/src/plugins/charts/kibana.json @@ -3,6 +3,7 @@ "version": "kibana", "server": true, "ui": true, + "extraPublicDirs": ["common"], "requiredPlugins": ["expressions"], "owner": { "name": "Vis Editors", diff --git a/src/plugins/charts/public/index.ts b/src/plugins/charts/public/index.ts index 6674b98fce910b..e3d38b797c576a 100644 --- a/src/plugins/charts/public/index.ts +++ b/src/plugins/charts/public/index.ts @@ -26,4 +26,19 @@ export { CustomPaletteState, SystemPaletteArguments, paletteIds, + ColorSchemas, + ColorSchema, + RawColorSchema, + ColorMap, + vislibColorMaps, + colorSchemas, + getHeatmapColors, + truncatedColorMaps, + truncatedColorSchemas, + ColorMode, + LabelRotation, + defaultCountLabel, + ColorSchemaParams, + Labels, + Style, } from '../common'; diff --git a/src/plugins/charts/public/mocks.ts b/src/plugins/charts/public/mocks.ts index 7460962c3e1fa6..a481f8ca138ceb 100644 --- a/src/plugins/charts/public/mocks.ts +++ b/src/plugins/charts/public/mocks.ts @@ -28,7 +28,7 @@ const createStartContract = (): Start => ({ palettes: paletteServiceMock.setup({} as any), }); -export { colorMapsMock } from './static/color_maps/mock'; +export { colorMapsMock } from '../common/static/color_maps/mock'; export const chartPluginMock = { createSetupContract, diff --git a/src/plugins/charts/public/static/components/index.ts b/src/plugins/charts/public/static/components/index.ts index 549218cf992aa1..7f3af50a01aa4a 100644 --- a/src/plugins/charts/public/static/components/index.ts +++ b/src/plugins/charts/public/static/components/index.ts @@ -6,8 +6,6 @@ * Side Public License, v 1. */ -export { ColorMode, LabelRotation, defaultCountLabel } from './collections'; -export { ColorSchemaParams, Labels, Style } from './types'; export { LegendToggle } from './legend_toggle'; export { ColorPicker } from './color_picker'; export { CurrentTime } from './current_time'; diff --git a/src/plugins/charts/public/static/index.ts b/src/plugins/charts/public/static/index.ts index 068ac8289e008f..6f5c87ce0df4d3 100644 --- a/src/plugins/charts/public/static/index.ts +++ b/src/plugins/charts/public/static/index.ts @@ -6,7 +6,6 @@ * Side Public License, v 1. */ -export * from './color_maps'; export * from './colors'; export * from './components'; export * from './utils'; diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts index dedc390c47719a..c01295f6ee42ce 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts @@ -515,7 +515,6 @@ export const useField = ( if (resetValue) { hasBeenReset.current = true; const newValue = deserializeValue(updatedDefaultValue ?? defaultValue); - // updateStateIfMounted('value', newValue); setValue(newValue); return newValue; } diff --git a/src/plugins/security_oss/README.md b/src/plugins/security_oss/README.md deleted file mode 100644 index 6143149fec3847..00000000000000 --- a/src/plugins/security_oss/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# `securityOss` plugin - -`securityOss` is responsible for educating users about Elastic's free security features, -so they can properly protect the data within their clusters. diff --git a/src/plugins/security_oss/kibana.json b/src/plugins/security_oss/kibana.json deleted file mode 100644 index c93b5c3b60714d..00000000000000 --- a/src/plugins/security_oss/kibana.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "id": "securityOss", - "owner": { - "name": "Platform Security", - "githubTeam": "kibana-security" - }, - "description": "This plugin exposes a limited set of security functionality to OSS plugins.", - "version": "8.0.0", - "kibanaVersion": "kibana", - "configPath": ["security"], - "ui": true, - "server": true, - "requiredPlugins": [], - "requiredBundles": [] -} diff --git a/src/plugins/security_oss/public/app_state/app_state_service.mock.ts b/src/plugins/security_oss/public/app_state/app_state_service.mock.ts deleted file mode 100644 index bfad596a9be2a3..00000000000000 --- a/src/plugins/security_oss/public/app_state/app_state_service.mock.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { AppState } from '../../common'; -import type { AppStateServiceStart } from './app_state_service'; - -export const mockAppStateService = { - createStart: (): jest.Mocked => { - return { getState: jest.fn() }; - }, - createAppState: (appState: Partial = {}) => ({ - insecureClusterAlert: { displayAlert: false }, - anonymousAccess: { isEnabled: false, accessURLParameters: null }, - ...appState, - }), -}; diff --git a/src/plugins/security_oss/public/app_state/app_state_service.test.ts b/src/plugins/security_oss/public/app_state/app_state_service.test.ts deleted file mode 100644 index ec491e0faac2f9..00000000000000 --- a/src/plugins/security_oss/public/app_state/app_state_service.test.ts +++ /dev/null @@ -1,62 +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 { coreMock } from 'src/core/public/mocks'; - -import { AppStateService } from './app_state_service'; - -describe('AppStateService', () => { - describe('#start', () => { - it('returns default state for the anonymous routes', async () => { - const coreStart = coreMock.createStart(); - coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(true); - - const appStateService = new AppStateService(); - await expect(appStateService.start({ core: coreStart }).getState()).resolves.toEqual({ - insecureClusterAlert: { displayAlert: false }, - anonymousAccess: { isEnabled: false, accessURLParameters: null }, - }); - - expect(coreStart.http.get).not.toHaveBeenCalled(); - }); - - it('returns default state if current state cannot be retrieved', async () => { - const coreStart = coreMock.createStart(); - coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); - - const failureReason = new Error('Uh oh.'); - coreStart.http.get.mockRejectedValue(failureReason); - - const appStateService = new AppStateService(); - await expect(appStateService.start({ core: coreStart }).getState()).resolves.toEqual({ - insecureClusterAlert: { displayAlert: false }, - anonymousAccess: { isEnabled: false, accessURLParameters: null }, - }); - - expect(coreStart.http.get).toHaveBeenCalledTimes(1); - expect(coreStart.http.get).toHaveBeenCalledWith('/internal/security_oss/app_state'); - }); - - it('returns retrieved state', async () => { - const coreStart = coreMock.createStart(); - coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); - - const state = { - insecureClusterAlert: { displayAlert: true }, - anonymousAccess: { isEnabled: true, accessURLParameters: { hint: 'some-hint' } }, - }; - coreStart.http.get.mockResolvedValue(state); - - const appStateService = new AppStateService(); - await expect(appStateService.start({ core: coreStart }).getState()).resolves.toEqual(state); - - expect(coreStart.http.get).toHaveBeenCalledTimes(1); - expect(coreStart.http.get).toHaveBeenCalledWith('/internal/security_oss/app_state'); - }); - }); -}); diff --git a/src/plugins/security_oss/public/app_state/app_state_service.ts b/src/plugins/security_oss/public/app_state/app_state_service.ts deleted file mode 100644 index 8f6e9c0f08e77f..00000000000000 --- a/src/plugins/security_oss/public/app_state/app_state_service.ts +++ /dev/null @@ -1,37 +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 type { CoreStart } from 'src/core/public'; - -import type { AppState } from '../../common'; - -const DEFAULT_APP_STATE = Object.freeze({ - insecureClusterAlert: { displayAlert: false }, - anonymousAccess: { isEnabled: false, accessURLParameters: null }, -}); - -interface StartDeps { - core: Pick; -} - -export interface AppStateServiceStart { - getState: () => Promise; -} - -/** - * Service that allows to retrieve application state. - */ -export class AppStateService { - start({ core }: StartDeps): AppStateServiceStart { - const appStatePromise = core.http.anonymousPaths.isAnonymous(window.location.pathname) - ? Promise.resolve(DEFAULT_APP_STATE) - : core.http.get('/internal/security_oss/app_state').catch(() => DEFAULT_APP_STATE); - - return { getState: () => appStatePromise }; - } -} diff --git a/src/plugins/security_oss/public/index.ts b/src/plugins/security_oss/public/index.ts deleted file mode 100644 index 0f67c6ed5442b5..00000000000000 --- a/src/plugins/security_oss/public/index.ts +++ /dev/null @@ -1,16 +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 type { PluginInitializerContext } from 'src/core/public'; - -import { SecurityOssPlugin } from './plugin'; - -export { SecurityOssPluginSetup, SecurityOssPluginStart } from './plugin'; - -export const plugin = (initializerContext: PluginInitializerContext) => - new SecurityOssPlugin(initializerContext); diff --git a/src/plugins/security_oss/public/insecure_cluster_service/components/default_alert.test.tsx b/src/plugins/security_oss/public/insecure_cluster_service/components/default_alert.test.tsx deleted file mode 100644 index 7664b69540c509..00000000000000 --- a/src/plugins/security_oss/public/insecure_cluster_service/components/default_alert.test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { defaultAlertText } from './default_alert'; - -describe('defaultAlertText', () => { - it('creates a valid MountPoint that can cleanup correctly', () => { - const mountPoint = defaultAlertText(jest.fn()); - - const el = document.createElement('div'); - const unmount = mountPoint(el); - - expect(el.querySelectorAll('[data-test-subj="insecureClusterDefaultAlertText"]')).toHaveLength( - 1 - ); - - unmount(); - - expect(el).toMatchInlineSnapshot(`
`); - }); -}); diff --git a/src/plugins/security_oss/public/insecure_cluster_service/components/default_alert.tsx b/src/plugins/security_oss/public/insecure_cluster_service/components/default_alert.tsx deleted file mode 100644 index 192be5188041b2..00000000000000 --- a/src/plugins/security_oss/public/insecure_cluster_service/components/default_alert.tsx +++ /dev/null @@ -1,86 +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 { - EuiButton, - EuiCheckbox, - EuiFlexGroup, - EuiFlexItem, - EuiSpacer, - EuiText, -} from '@elastic/eui'; -import React, { useState } from 'react'; -import { render, unmountComponentAtNode } from 'react-dom'; - -import { i18n } from '@kbn/i18n'; -import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; -import type { MountPoint } from 'src/core/public'; - -export const defaultAlertTitle = i18n.translate('security.checkup.insecureClusterTitle', { - defaultMessage: 'Your data is not secure', -}); - -export const defaultAlertText: (onDismiss: (persist: boolean) => void) => MountPoint = - (onDismiss) => (e) => { - const AlertText = () => { - const [persist, setPersist] = useState(false); - - return ( - -
- - - - - setPersist(changeEvent.target.checked)} - label={i18n.translate('security.checkup.dontShowAgain', { - defaultMessage: `Don't show again`, - })} - /> - - - - - {i18n.translate('security.checkup.learnMoreButtonText', { - defaultMessage: `Learn more`, - })} - - - - onDismiss(persist)} - data-test-subj="defaultDismissAlertButton" - > - {i18n.translate('security.checkup.dismissButtonText', { - defaultMessage: `Dismiss`, - })} - - - -
-
- ); - }; - - render(, e); - - return () => unmountComponentAtNode(e); - }; diff --git a/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.mock.tsx b/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.mock.tsx deleted file mode 100644 index accf597aafa0b7..00000000000000 --- a/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.mock.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { - InsecureClusterServiceSetup, - InsecureClusterServiceStart, -} from './insecure_cluster_service'; - -export const mockInsecureClusterService = { - createSetup: () => { - return { - setAlertTitle: jest.fn(), - setAlertText: jest.fn(), - } as InsecureClusterServiceSetup; - }, - createStart: () => { - return { - hideAlert: jest.fn(), - } as InsecureClusterServiceStart; - }, -}; diff --git a/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.test.tsx b/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.test.tsx deleted file mode 100644 index 25eae0b11c5195..00000000000000 --- a/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.test.tsx +++ /dev/null @@ -1,342 +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 { nextTick } from '@kbn/test/jest'; -import { coreMock } from 'src/core/public/mocks'; - -import { mockAppStateService } from '../app_state/app_state_service.mock'; -import type { ConfigType } from '../config'; -import { InsecureClusterService } from './insecure_cluster_service'; - -let mockOnDismissCallback: (persist: boolean) => void = jest.fn().mockImplementation(() => { - throw new Error('expected callback to be replaced!'); -}); - -jest.mock('./components', () => { - return { - defaultAlertTitle: 'mocked default alert title', - defaultAlertText: (onDismiss: any) => { - mockOnDismissCallback = onDismiss; - return 'mocked default alert text'; - }, - }; -}); - -interface InitOpts { - tenant?: string; -} - -function initCore({ tenant = '/server-base-path' }: InitOpts = {}) { - const coreSetup = coreMock.createSetup(); - (coreSetup.http.basePath.serverBasePath as string) = tenant; - - const coreStart = coreMock.createStart(); - coreStart.notifications.toasts.addWarning.mockReturnValue({ id: 'mock_alert_id' }); - return { coreSetup, coreStart }; -} - -describe('InsecureClusterService', () => { - describe('display scenarios', () => { - it('does not display an alert when the warning is explicitly disabled via config', async () => { - const config: ConfigType = { showInsecureClusterWarning: false }; - const { coreSetup, coreStart } = initCore(); - const storage = coreMock.createStorage(); - - const appState = mockAppStateService.createStart(); - appState.getState.mockResolvedValue( - mockAppStateService.createAppState({ insecureClusterAlert: { displayAlert: true } }) - ); - - const service = new InsecureClusterService(config, storage); - service.setup({ core: coreSetup }); - service.start({ core: coreStart, appState }); - - await nextTick(); - - expect(appState.getState).not.toHaveBeenCalled(); - expect(coreStart.notifications.toasts.addWarning).not.toHaveBeenCalled(); - - expect(coreStart.notifications.toasts.remove).not.toHaveBeenCalled(); - expect(storage.setItem).not.toHaveBeenCalled(); - }); - - it('does not display an alert when state indicates that alert should not be shown', async () => { - const config: ConfigType = { showInsecureClusterWarning: true }; - const { coreSetup, coreStart } = initCore(); - const storage = coreMock.createStorage(); - - const appState = mockAppStateService.createStart(); - appState.getState.mockResolvedValue( - mockAppStateService.createAppState({ insecureClusterAlert: { displayAlert: false } }) - ); - - const service = new InsecureClusterService(config, storage); - service.setup({ core: coreSetup }); - service.start({ core: coreStart, appState }); - - await nextTick(); - - expect(appState.getState).toHaveBeenCalledTimes(1); - expect(coreStart.notifications.toasts.addWarning).not.toHaveBeenCalled(); - - expect(coreStart.notifications.toasts.remove).not.toHaveBeenCalled(); - expect(storage.setItem).not.toHaveBeenCalled(); - }); - - it('only reads storage information from the current tenant', async () => { - const config: ConfigType = { showInsecureClusterWarning: true }; - const { coreSetup, coreStart } = initCore({ tenant: '/my-specific-tenant' }); - - const storage = coreMock.createStorage(); - storage.getItem.mockReturnValue(JSON.stringify({ show: false })); - - const appState = mockAppStateService.createStart(); - appState.getState.mockResolvedValue( - mockAppStateService.createAppState({ insecureClusterAlert: { displayAlert: true } }) - ); - - const service = new InsecureClusterService(config, storage); - service.setup({ core: coreSetup }); - service.start({ core: coreStart, appState }); - - await nextTick(); - - expect(storage.getItem).toHaveBeenCalledTimes(1); - expect(storage.getItem).toHaveBeenCalledWith( - 'insecureClusterWarningVisibility/my-specific-tenant' - ); - }); - - it('does not display an alert when hidden via storage', async () => { - const config: ConfigType = { showInsecureClusterWarning: true }; - const { coreSetup, coreStart } = initCore(); - - const storage = coreMock.createStorage(); - storage.getItem.mockReturnValue(JSON.stringify({ show: false })); - - const appState = mockAppStateService.createStart(); - appState.getState.mockResolvedValue( - mockAppStateService.createAppState({ insecureClusterAlert: { displayAlert: true } }) - ); - - const service = new InsecureClusterService(config, storage); - service.setup({ core: coreSetup }); - service.start({ core: coreStart, appState }); - - await nextTick(); - - expect(appState.getState).not.toHaveBeenCalled(); - expect(coreStart.notifications.toasts.addWarning).not.toHaveBeenCalled(); - - expect(coreStart.notifications.toasts.remove).not.toHaveBeenCalled(); - expect(storage.setItem).not.toHaveBeenCalled(); - }); - - it('displays an alert when persisted preference is corrupted', async () => { - const config: ConfigType = { showInsecureClusterWarning: true }; - const { coreSetup, coreStart } = initCore(); - - const storage = coreMock.createStorage(); - storage.getItem.mockReturnValue('{ this is a string of invalid JSON'); - - const appState = mockAppStateService.createStart(); - appState.getState.mockResolvedValue( - mockAppStateService.createAppState({ insecureClusterAlert: { displayAlert: true } }) - ); - - const service = new InsecureClusterService(config, storage); - service.setup({ core: coreSetup }); - service.start({ core: coreStart, appState }); - - await nextTick(); - - expect(appState.getState).toHaveBeenCalledTimes(1); - expect(coreStart.notifications.toasts.addWarning).toHaveBeenCalledTimes(1); - - expect(coreStart.notifications.toasts.remove).not.toHaveBeenCalled(); - expect(storage.setItem).not.toHaveBeenCalled(); - }); - - it('displays an alert when enabled via config and endpoint checks', async () => { - const config: ConfigType = { showInsecureClusterWarning: true }; - const { coreSetup, coreStart } = initCore(); - const storage = coreMock.createStorage(); - - const appState = mockAppStateService.createStart(); - appState.getState.mockResolvedValue( - mockAppStateService.createAppState({ insecureClusterAlert: { displayAlert: true } }) - ); - - const service = new InsecureClusterService(config, storage); - service.setup({ core: coreSetup }); - service.start({ core: coreStart, appState }); - - await nextTick(); - - expect(appState.getState).toHaveBeenCalledTimes(1); - expect(coreStart.notifications.toasts.addWarning).toHaveBeenCalledTimes(1); - expect(coreStart.notifications.toasts.addWarning.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "iconType": "alert", - "text": "mocked default alert text", - "title": "mocked default alert title", - }, - Object { - "toastLifeTimeMs": 864000000, - }, - ] - `); - - expect(coreStart.notifications.toasts.remove).not.toHaveBeenCalled(); - expect(storage.setItem).not.toHaveBeenCalled(); - }); - - it('dismisses the alert when requested, and remembers this preference', async () => { - const config: ConfigType = { showInsecureClusterWarning: true }; - const { coreSetup, coreStart } = initCore(); - const storage = coreMock.createStorage(); - - const appState = mockAppStateService.createStart(); - appState.getState.mockResolvedValue( - mockAppStateService.createAppState({ insecureClusterAlert: { displayAlert: true } }) - ); - - const service = new InsecureClusterService(config, storage); - service.setup({ core: coreSetup }); - service.start({ core: coreStart, appState }); - - await nextTick(); - - expect(appState.getState).toHaveBeenCalledTimes(1); - expect(coreStart.notifications.toasts.addWarning).toHaveBeenCalledTimes(1); - - mockOnDismissCallback(true); - - expect(coreStart.notifications.toasts.remove).toHaveBeenCalledTimes(1); - expect(storage.setItem).toHaveBeenCalledWith( - 'insecureClusterWarningVisibility/server-base-path', - JSON.stringify({ show: false }) - ); - }); - }); - - describe('#setup', () => { - it('allows the alert title and text to be replaced exactly once', async () => { - const config: ConfigType = { showInsecureClusterWarning: true }; - const storage = coreMock.createStorage(); - - const { coreSetup } = initCore(); - - const service = new InsecureClusterService(config, storage); - const { setAlertTitle, setAlertText } = service.setup({ core: coreSetup }); - setAlertTitle('some new title'); - setAlertText('some new alert text'); - - expect(() => setAlertTitle('')).toThrowErrorMatchingInlineSnapshot( - `"alert title has already been set"` - ); - expect(() => setAlertText('')).toThrowErrorMatchingInlineSnapshot( - `"alert text has already been set"` - ); - }); - - it('allows the alert title and text to be replaced', async () => { - const config: ConfigType = { showInsecureClusterWarning: true }; - const { coreSetup, coreStart } = initCore(); - const storage = coreMock.createStorage(); - - const appState = mockAppStateService.createStart(); - appState.getState.mockResolvedValue( - mockAppStateService.createAppState({ insecureClusterAlert: { displayAlert: true } }) - ); - - const service = new InsecureClusterService(config, storage); - const { setAlertTitle, setAlertText } = service.setup({ core: coreSetup }); - setAlertTitle('some new title'); - setAlertText('some new alert text'); - - service.start({ core: coreStart, appState }); - - await nextTick(); - - expect(appState.getState).toHaveBeenCalledTimes(1); - expect(coreStart.notifications.toasts.addWarning).toHaveBeenCalledTimes(1); - expect(coreStart.notifications.toasts.addWarning.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "iconType": "alert", - "text": "some new alert text", - "title": "some new title", - }, - Object { - "toastLifeTimeMs": 864000000, - }, - ] - `); - - expect(coreStart.notifications.toasts.remove).not.toHaveBeenCalled(); - expect(storage.setItem).not.toHaveBeenCalled(); - }); - }); - - describe('#start', () => { - it('allows the alert to be hidden via start contract, and remembers this preference', async () => { - const config: ConfigType = { showInsecureClusterWarning: true }; - const { coreSetup, coreStart } = initCore(); - const storage = coreMock.createStorage(); - - const appState = mockAppStateService.createStart(); - appState.getState.mockResolvedValue( - mockAppStateService.createAppState({ insecureClusterAlert: { displayAlert: true } }) - ); - - const service = new InsecureClusterService(config, storage); - service.setup({ core: coreSetup }); - const { hideAlert } = service.start({ core: coreStart, appState }); - - await nextTick(); - - expect(appState.getState).toHaveBeenCalledTimes(1); - expect(coreStart.notifications.toasts.addWarning).toHaveBeenCalledTimes(1); - - hideAlert(true); - - expect(coreStart.notifications.toasts.remove).toHaveBeenCalledTimes(1); - expect(storage.setItem).toHaveBeenCalledWith( - 'insecureClusterWarningVisibility/server-base-path', - JSON.stringify({ show: false }) - ); - }); - - it('allows the alert to be hidden via start contract, and does not remember the preference', async () => { - const config: ConfigType = { showInsecureClusterWarning: true }; - const { coreSetup, coreStart } = initCore(); - const storage = coreMock.createStorage(); - - const appState = mockAppStateService.createStart(); - appState.getState.mockResolvedValue( - mockAppStateService.createAppState({ insecureClusterAlert: { displayAlert: true } }) - ); - - const service = new InsecureClusterService(config, storage); - service.setup({ core: coreSetup }); - const { hideAlert } = service.start({ core: coreStart, appState }); - - await nextTick(); - - expect(appState.getState).toHaveBeenCalledTimes(1); - expect(coreStart.notifications.toasts.addWarning).toHaveBeenCalledTimes(1); - - hideAlert(false); - - expect(coreStart.notifications.toasts.remove).toHaveBeenCalledTimes(1); - expect(storage.setItem).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.tsx b/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.tsx deleted file mode 100644 index 6cb2079cbe954f..00000000000000 --- a/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.tsx +++ /dev/null @@ -1,149 +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 { BehaviorSubject, combineLatest, from } from 'rxjs'; -import { distinctUntilChanged, map } from 'rxjs/operators'; - -import type { CoreSetup, CoreStart, MountPoint, Toast } from 'src/core/public'; - -import type { AppStateServiceStart } from '../app_state'; -import type { ConfigType } from '../config'; -import { defaultAlertText, defaultAlertTitle } from './components'; - -interface SetupDeps { - core: Pick; -} - -interface StartDeps { - core: Pick; - appState: AppStateServiceStart; -} - -export interface InsecureClusterServiceSetup { - setAlertTitle: (alertTitle: string | MountPoint) => void; - setAlertText: (alertText: string | MountPoint) => void; -} - -export interface InsecureClusterServiceStart { - hideAlert: (persist: boolean) => void; -} - -export class InsecureClusterService { - private enabled: boolean; - - private alertVisibility$: BehaviorSubject; - - private storage: Storage; - - private alertToast?: Toast; - - private alertTitle?: string | MountPoint; - - private alertText?: string | MountPoint; - - private storageKey?: string; - - constructor(config: Pick, storage: Storage) { - this.storage = storage; - this.enabled = config.showInsecureClusterWarning; - this.alertVisibility$ = new BehaviorSubject(this.enabled); - } - - public setup({ core }: SetupDeps): InsecureClusterServiceSetup { - const tenant = core.http.basePath.serverBasePath; - this.storageKey = `insecureClusterWarningVisibility${tenant}`; - this.enabled = this.enabled && this.getPersistedVisibilityPreference(); - this.alertVisibility$.next(this.enabled); - - return { - setAlertTitle: (alertTitle: string | MountPoint) => { - if (this.alertTitle) { - throw new Error('alert title has already been set'); - } - this.alertTitle = alertTitle; - }, - setAlertText: (alertText: string | MountPoint) => { - if (this.alertText) { - throw new Error('alert text has already been set'); - } - this.alertText = alertText; - }, - }; - } - - public start({ core, appState }: StartDeps): InsecureClusterServiceStart { - if (this.enabled) { - this.initializeAlert(core, appState); - } - - return { - hideAlert: (persist: boolean) => this.setAlertVisibility(false, persist), - }; - } - - private initializeAlert(core: StartDeps['core'], appState: AppStateServiceStart) { - const appState$ = from(appState.getState()); - - // 10 days is reasonably long enough to call "forever" for a page load. - // Can't go too much longer than this. See https://github.com/elastic/kibana/issues/64264#issuecomment-618400354 - const oneMinute = 60000; - const tenDays = oneMinute * 60 * 24 * 10; - - combineLatest([appState$, this.alertVisibility$]) - .pipe( - map( - ([{ insecureClusterAlert }, isAlertVisible]) => - insecureClusterAlert.displayAlert && isAlertVisible - ), - distinctUntilChanged() - ) - .subscribe((showAlert) => { - if (showAlert && !this.alertToast) { - this.alertToast = core.notifications.toasts.addWarning( - { - title: this.alertTitle ?? defaultAlertTitle, - text: - this.alertText ?? - defaultAlertText((persist: boolean) => this.setAlertVisibility(false, persist)), - iconType: 'alert', - }, - { - toastLifeTimeMs: tenDays, - } - ); - } else if (!showAlert && this.alertToast) { - core.notifications.toasts.remove(this.alertToast); - this.alertToast = undefined; - } - }); - } - - private setAlertVisibility(show: boolean, persist: boolean) { - if (!this.enabled) { - return; - } - this.alertVisibility$.next(show); - if (persist) { - this.setPersistedVisibilityPreference(show); - } - } - - private getPersistedVisibilityPreference() { - const entry = this.storage.getItem(this.storageKey!) ?? '{}'; - try { - const { show = true } = JSON.parse(entry); - return show; - } catch (e) { - return true; - } - } - - private setPersistedVisibilityPreference(show: boolean) { - this.storage.setItem(this.storageKey!, JSON.stringify({ show })); - } -} diff --git a/src/plugins/security_oss/public/plugin.mock.ts b/src/plugins/security_oss/public/plugin.mock.ts deleted file mode 100644 index 23a6050a0e501d..00000000000000 --- a/src/plugins/security_oss/public/plugin.mock.ts +++ /dev/null @@ -1,31 +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 type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; - -import type { InsecureClusterServiceStart } from './insecure_cluster_service'; -import { mockInsecureClusterService } from './insecure_cluster_service/insecure_cluster_service.mock'; -import type { SecurityOssPluginSetup, SecurityOssPluginStart } from './plugin'; - -export const mockSecurityOssPlugin = { - createSetup: () => { - return { - insecureCluster: mockInsecureClusterService.createSetup(), - } as DeeplyMockedKeys; - }, - createStart: () => { - return { - insecureCluster: - mockInsecureClusterService.createStart() as jest.Mocked, - anonymousAccess: { - getAccessURLParameters: jest.fn().mockResolvedValue(null), - getCapabilities: jest.fn().mockResolvedValue({}), - }, - } as DeeplyMockedKeys; - }, -}; diff --git a/src/plugins/security_oss/public/plugin.ts b/src/plugins/security_oss/public/plugin.ts deleted file mode 100644 index c26323b01f3568..00000000000000 --- a/src/plugins/security_oss/public/plugin.ts +++ /dev/null @@ -1,69 +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 type { - Capabilities, - CoreSetup, - CoreStart, - Plugin, - PluginInitializerContext, -} from 'src/core/public'; - -import { AppStateService } from './app_state'; -import type { ConfigType } from './config'; -import type { - InsecureClusterServiceSetup, - InsecureClusterServiceStart, -} from './insecure_cluster_service'; -import { InsecureClusterService } from './insecure_cluster_service'; - -export interface SecurityOssPluginSetup { - insecureCluster: InsecureClusterServiceSetup; -} - -export interface SecurityOssPluginStart { - insecureCluster: InsecureClusterServiceStart; - anonymousAccess: { - getAccessURLParameters: () => Promise | null>; - getCapabilities: () => Promise; - }; -} - -export class SecurityOssPlugin - implements Plugin -{ - private readonly config = this.initializerContext.config.get(); - private readonly insecureClusterService = new InsecureClusterService(this.config, localStorage); - private readonly appStateService = new AppStateService(); - - constructor(private readonly initializerContext: PluginInitializerContext) {} - - public setup(core: CoreSetup) { - return { - insecureCluster: this.insecureClusterService.setup({ core }), - }; - } - - public start(core: CoreStart) { - const appState = this.appStateService.start({ core }); - return { - insecureCluster: this.insecureClusterService.start({ core, appState }), - anonymousAccess: { - async getAccessURLParameters() { - const { anonymousAccess } = await appState.getState(); - return anonymousAccess.accessURLParameters; - }, - getCapabilities() { - return core.http.get( - '/internal/security_oss/anonymous_access/capabilities' - ); - }, - }, - }; - } -} diff --git a/src/plugins/security_oss/server/config.ts b/src/plugins/security_oss/server/config.ts deleted file mode 100644 index 4be4bf96c2d824..00000000000000 --- a/src/plugins/security_oss/server/config.ts +++ /dev/null @@ -1,16 +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 type { TypeOf } from '@kbn/config-schema'; -import { schema } from '@kbn/config-schema'; - -export type ConfigType = TypeOf; - -export const ConfigSchema = schema.object({ - showInsecureClusterWarning: schema.boolean({ defaultValue: true }), -}); diff --git a/src/plugins/security_oss/server/index.ts b/src/plugins/security_oss/server/index.ts deleted file mode 100644 index 42736302b5d266..00000000000000 --- a/src/plugins/security_oss/server/index.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 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 { TypeOf } from '@kbn/config-schema'; -import type { PluginConfigDescriptor, PluginInitializerContext } from 'src/core/server'; - -import { ConfigSchema } from './config'; -import { SecurityOssPlugin } from './plugin'; - -export { SecurityOssPluginSetup } from './plugin'; - -export const config: PluginConfigDescriptor> = { - schema: ConfigSchema, - exposeToBrowser: { - showInsecureClusterWarning: true, - }, -}; - -export const plugin = (context: PluginInitializerContext) => new SecurityOssPlugin(context); diff --git a/src/plugins/security_oss/server/plugin.test.ts b/src/plugins/security_oss/server/plugin.test.ts deleted file mode 100644 index 5858fabd6a7062..00000000000000 --- a/src/plugins/security_oss/server/plugin.test.ts +++ /dev/null @@ -1,28 +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 { coreMock } from 'src/core/server/mocks'; - -import { SecurityOssPlugin } from './plugin'; - -describe('SecurityOss Plugin', () => { - describe('#setup', () => { - it('exposes the proper contract', async () => { - const context = coreMock.createPluginInitializerContext(); - const plugin = new SecurityOssPlugin(context); - const core = coreMock.createSetup(); - const contract = plugin.setup(core); - expect(Object.keys(contract)).toMatchInlineSnapshot(` - Array [ - "showInsecureClusterWarning$", - "setAnonymousAccessServiceProvider", - ] - `); - }); - }); -}); diff --git a/src/plugins/security_oss/server/plugin.ts b/src/plugins/security_oss/server/plugin.ts deleted file mode 100644 index 6adea272ed4900..00000000000000 --- a/src/plugins/security_oss/server/plugin.ts +++ /dev/null @@ -1,100 +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 type { Observable } from 'rxjs'; -import { BehaviorSubject } from 'rxjs'; - -import type { - Capabilities, - CoreSetup, - KibanaRequest, - Logger, - Plugin, - PluginInitializerContext, -} from 'src/core/server'; - -import { createClusterDataCheck } from './check_cluster_data'; -import type { ConfigType } from './config'; -import { setupAnonymousAccessCapabilitiesRoute, setupAppStateRoute } from './routes'; - -export interface SecurityOssPluginSetup { - /** - * Allows consumers to show/hide the insecure cluster warning. - */ - showInsecureClusterWarning$: BehaviorSubject; - - /** - * Set the provider function that returns a service to deal with the anonymous access. - * @param provider - */ - setAnonymousAccessServiceProvider: (provider: () => AnonymousAccessService) => void; -} - -export interface AnonymousAccessService { - /** - * Indicates whether anonymous access is enabled. - */ - readonly isAnonymousAccessEnabled: boolean; - - /** - * A map of query string parameters that should be specified in the URL pointing to Kibana so - * that anonymous user can automatically log in. - */ - readonly accessURLParameters: Readonly> | null; - - /** - * Gets capabilities of the anonymous service account. - * @param request Kibana request instance. - */ - getCapabilities: (request: KibanaRequest) => Promise; -} - -export class SecurityOssPlugin implements Plugin { - private readonly config$: Observable; - private readonly logger: Logger; - private anonymousAccessServiceProvider?: () => AnonymousAccessService; - - constructor(initializerContext: PluginInitializerContext) { - this.config$ = initializerContext.config.create(); - this.logger = initializerContext.logger.get(); - } - - public setup(core: CoreSetup) { - const router = core.http.createRouter(); - const showInsecureClusterWarning$ = new BehaviorSubject(true); - - setupAppStateRoute({ - router, - log: this.logger, - config$: this.config$, - displayModifier$: showInsecureClusterWarning$, - doesClusterHaveUserData: createClusterDataCheck(), - getAnonymousAccessService: () => this.anonymousAccessServiceProvider?.() ?? null, - }); - - setupAnonymousAccessCapabilitiesRoute({ - router, - getAnonymousAccessService: () => this.anonymousAccessServiceProvider?.() ?? null, - }); - - return { - showInsecureClusterWarning$, - setAnonymousAccessServiceProvider: (provider: () => AnonymousAccessService) => { - if (this.anonymousAccessServiceProvider) { - throw new Error('Anonymous Access service provider is already set.'); - } - - this.anonymousAccessServiceProvider = provider; - }, - }; - } - - public start() {} - - public stop() {} -} diff --git a/src/plugins/security_oss/server/routes/anonymous_access_capabilities.ts b/src/plugins/security_oss/server/routes/anonymous_access_capabilities.ts deleted file mode 100644 index 80273b41063add..00000000000000 --- a/src/plugins/security_oss/server/routes/anonymous_access_capabilities.ts +++ /dev/null @@ -1,33 +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 type { IRouter } from 'src/core/server'; - -import type { AnonymousAccessService } from '../plugin'; - -interface Deps { - router: IRouter; - getAnonymousAccessService: () => AnonymousAccessService | null; -} - -/** - * Defines route that returns capabilities of the anonymous service account. - */ -export function setupAnonymousAccessCapabilitiesRoute({ router, getAnonymousAccessService }: Deps) { - router.get( - { path: '/internal/security_oss/anonymous_access/capabilities', validate: false }, - async (_context, request, response) => { - const anonymousAccessService = getAnonymousAccessService(); - if (!anonymousAccessService) { - return response.custom({ statusCode: 501, body: 'Not Implemented' }); - } - - return response.ok({ body: await anonymousAccessService.getCapabilities(request) }); - } - ); -} diff --git a/src/plugins/security_oss/server/routes/app_state.ts b/src/plugins/security_oss/server/routes/app_state.ts deleted file mode 100644 index 6ecac362559d11..00000000000000 --- a/src/plugins/security_oss/server/routes/app_state.ts +++ /dev/null @@ -1,66 +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 type { Observable } from 'rxjs'; -import { combineLatest } from 'rxjs'; - -import type { IRouter, Logger } from 'src/core/server'; - -import type { AppState } from '../../common'; -import type { createClusterDataCheck } from '../check_cluster_data'; -import type { ConfigType } from '../config'; -import type { AnonymousAccessService } from '../plugin'; - -interface Deps { - router: IRouter; - log: Logger; - config$: Observable; - displayModifier$: Observable; - doesClusterHaveUserData: ReturnType; - getAnonymousAccessService: () => AnonymousAccessService | null; -} - -export const setupAppStateRoute = ({ - router, - log, - config$, - displayModifier$, - doesClusterHaveUserData, - getAnonymousAccessService, -}: Deps) => { - let showInsecureClusterWarning = false; - - combineLatest([config$, displayModifier$]).subscribe(([config, displayModifier]) => { - showInsecureClusterWarning = config.showInsecureClusterWarning && displayModifier; - }); - - router.get( - { path: '/internal/security_oss/app_state', validate: false }, - async (context, request, response) => { - let displayAlert = false; - if (showInsecureClusterWarning) { - displayAlert = await doesClusterHaveUserData( - context.core.elasticsearch.client.asInternalUser, - log - ); - } - - const anonymousAccessService = getAnonymousAccessService(); - const appState: AppState = { - insecureClusterAlert: { displayAlert }, - anonymousAccess: { - isEnabled: anonymousAccessService?.isAnonymousAccessEnabled ?? false, - accessURLParameters: anonymousAccessService?.accessURLParameters - ? Object.fromEntries(anonymousAccessService.accessURLParameters.entries()) - : null, - }, - }; - return response.ok({ body: appState }); - } - ); -}; diff --git a/src/plugins/security_oss/server/routes/index.ts b/src/plugins/security_oss/server/routes/index.ts deleted file mode 100644 index bde267dd44f8c2..00000000000000 --- a/src/plugins/security_oss/server/routes/index.ts +++ /dev/null @@ -1,10 +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. - */ - -export { setupAppStateRoute } from './app_state'; -export { setupAnonymousAccessCapabilitiesRoute } from './anonymous_access_capabilities'; diff --git a/src/plugins/security_oss/server/routes/integration_tests/anonymous_access_capabilities.test.ts b/src/plugins/security_oss/server/routes/integration_tests/anonymous_access_capabilities.test.ts deleted file mode 100644 index 0dba0433a36258..00000000000000 --- a/src/plugins/security_oss/server/routes/integration_tests/anonymous_access_capabilities.test.ts +++ /dev/null @@ -1,77 +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 supertest from 'supertest'; - -import type { UnwrapPromise } from '@kbn/utility-types'; -import { setupServer } from 'src/core/server/test_utils'; - -import type { AnonymousAccessService } from '../../plugin'; -import { setupAnonymousAccessCapabilitiesRoute } from '../anonymous_access_capabilities'; - -type SetupServerReturn = UnwrapPromise>; -const pluginId = Symbol('securityOss'); - -interface SetupOpts { - getAnonymousAccessService?: () => AnonymousAccessService | null; -} - -describe('GET /internal/security_oss/anonymous_access/capabilities', () => { - let server: SetupServerReturn['server']; - let httpSetup: SetupServerReturn['httpSetup']; - - const setupTestServer = async ({ getAnonymousAccessService = () => null }: SetupOpts = {}) => { - ({ server, httpSetup } = await setupServer(pluginId)); - - const router = httpSetup.createRouter('/'); - - setupAnonymousAccessCapabilitiesRoute({ router, getAnonymousAccessService }); - - await server.start(); - }; - - afterEach(async () => { - await server.stop(); - }); - - it('responds with 501 if anonymous access service is provided', async () => { - await setupTestServer(); - - await supertest(httpSetup.server.listener) - .get('/internal/security_oss/anonymous_access/capabilities') - .expect(501, { - statusCode: 501, - error: 'Not Implemented', - message: 'Not Implemented', - }); - }); - - it('returns anonymous access state if anonymous access service is provided', async () => { - await setupTestServer({ - getAnonymousAccessService: () => ({ - isAnonymousAccessEnabled: true, - accessURLParameters: new Map([['auth_provider_hint', 'anonymous1']]), - getCapabilities: jest.fn().mockResolvedValue({ - navLinks: {}, - management: {}, - catalogue: {}, - custom: { something: true }, - }), - }), - }); - - await supertest(httpSetup.server.listener) - .get('/internal/security_oss/anonymous_access/capabilities') - .expect(200, { - navLinks: {}, - management: {}, - catalogue: {}, - custom: { something: true }, - }); - }); -}); diff --git a/src/plugins/security_oss/server/routes/integration_tests/app_state.test.ts b/src/plugins/security_oss/server/routes/integration_tests/app_state.test.ts deleted file mode 100644 index 82e7098760e184..00000000000000 --- a/src/plugins/security_oss/server/routes/integration_tests/app_state.test.ts +++ /dev/null @@ -1,184 +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 { BehaviorSubject, of } from 'rxjs'; -import supertest from 'supertest'; - -import type { UnwrapPromise } from '@kbn/utility-types'; -import { loggingSystemMock } from 'src/core/server/mocks'; -import { setupServer } from 'src/core/server/test_utils'; - -import type { createClusterDataCheck } from '../../check_cluster_data'; -import type { ConfigType } from '../../config'; -import type { AnonymousAccessService } from '../../plugin'; -import { setupAppStateRoute } from '../app_state'; - -type SetupServerReturn = UnwrapPromise>; -const pluginId = Symbol('securityOss'); - -interface SetupOpts { - config?: ConfigType; - displayModifier$?: BehaviorSubject; - doesClusterHaveUserData?: ReturnType; - getAnonymousAccessService?: () => AnonymousAccessService | null; -} - -describe('GET /internal/security_oss/app_state', () => { - let server: SetupServerReturn['server']; - let httpSetup: SetupServerReturn['httpSetup']; - - const setupTestServer = async ({ - config = { showInsecureClusterWarning: true }, - displayModifier$ = new BehaviorSubject(true), - doesClusterHaveUserData = jest.fn().mockResolvedValue(true), - getAnonymousAccessService = () => null, - }: SetupOpts) => { - ({ server, httpSetup } = await setupServer(pluginId)); - - const router = httpSetup.createRouter('/'); - const log = loggingSystemMock.createLogger(); - - setupAppStateRoute({ - router, - log, - config$: of(config), - displayModifier$, - doesClusterHaveUserData, - getAnonymousAccessService, - }); - - await server.start(); - - return { - log, - }; - }; - - afterEach(async () => { - await server.stop(); - }); - - it('responds `insecureClusterAlert.displayAlert == false` if plugin is not configured to display alerts', async () => { - await setupTestServer({ - config: { showInsecureClusterWarning: false }, - }); - - await supertest(httpSetup.server.listener) - .get('/internal/security_oss/app_state') - .expect(200, { - insecureClusterAlert: { displayAlert: false }, - anonymousAccess: { isEnabled: false, accessURLParameters: null }, - }); - }); - - it('responds `insecureClusterAlert.displayAlert == false` if cluster does not contain user data', async () => { - await setupTestServer({ - config: { showInsecureClusterWarning: true }, - doesClusterHaveUserData: jest.fn().mockResolvedValue(false), - }); - - await supertest(httpSetup.server.listener) - .get('/internal/security_oss/app_state') - .expect(200, { - insecureClusterAlert: { displayAlert: false }, - anonymousAccess: { isEnabled: false, accessURLParameters: null }, - }); - }); - - it('responds `insecureClusterAlert.displayAlert == false` if displayModifier$ is set to false', async () => { - await setupTestServer({ - config: { showInsecureClusterWarning: true }, - doesClusterHaveUserData: jest.fn().mockResolvedValue(true), - displayModifier$: new BehaviorSubject(false), - }); - - await supertest(httpSetup.server.listener) - .get('/internal/security_oss/app_state') - .expect(200, { - insecureClusterAlert: { displayAlert: false }, - anonymousAccess: { isEnabled: false, accessURLParameters: null }, - }); - }); - - it('responds `insecureClusterAlert.displayAlert == true` if cluster contains user data', async () => { - await setupTestServer({ - config: { showInsecureClusterWarning: true }, - doesClusterHaveUserData: jest.fn().mockResolvedValue(true), - }); - - await supertest(httpSetup.server.listener) - .get('/internal/security_oss/app_state') - .expect(200, { - insecureClusterAlert: { displayAlert: true }, - anonymousAccess: { isEnabled: false, accessURLParameters: null }, - }); - }); - - it('responds to changing displayModifier$ values', async () => { - const displayModifier$ = new BehaviorSubject(true); - - await setupTestServer({ - config: { showInsecureClusterWarning: true }, - doesClusterHaveUserData: jest.fn().mockResolvedValue(true), - displayModifier$, - }); - - await supertest(httpSetup.server.listener) - .get('/internal/security_oss/app_state') - .expect(200, { - insecureClusterAlert: { displayAlert: true }, - anonymousAccess: { isEnabled: false, accessURLParameters: null }, - }); - - displayModifier$.next(false); - - await supertest(httpSetup.server.listener) - .get('/internal/security_oss/app_state') - .expect(200, { - insecureClusterAlert: { displayAlert: false }, - anonymousAccess: { isEnabled: false, accessURLParameters: null }, - }); - }); - - it('returns anonymous access state if anonymous access service is provided', async () => { - const displayModifier$ = new BehaviorSubject(true); - - await setupTestServer({ - config: { showInsecureClusterWarning: true }, - doesClusterHaveUserData: jest.fn().mockResolvedValue(true), - displayModifier$, - getAnonymousAccessService: () => ({ - isAnonymousAccessEnabled: true, - accessURLParameters: new Map([['auth_provider_hint', 'anonymous1']]), - getCapabilities: jest.fn(), - }), - }); - - await supertest(httpSetup.server.listener) - .get('/internal/security_oss/app_state') - .expect(200, { - insecureClusterAlert: { displayAlert: true }, - anonymousAccess: { - isEnabled: true, - accessURLParameters: { auth_provider_hint: 'anonymous1' }, - }, - }); - - displayModifier$.next(false); - - await supertest(httpSetup.server.listener) - .get('/internal/security_oss/app_state') - .expect(200, { - insecureClusterAlert: { displayAlert: false }, - anonymousAccess: { - isEnabled: true, - accessURLParameters: { auth_provider_hint: 'anonymous1' }, - }, - }); - }); -}); diff --git a/src/plugins/security_oss/tsconfig.json b/src/plugins/security_oss/tsconfig.json deleted file mode 100644 index 6ebeff836f69b6..00000000000000 --- a/src/plugins/security_oss/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./target/types", - "emitDeclarationOnly": true, - "declaration": true, - "declarationMap": true - }, - "include": ["common/**/*", "public/**/*", "server/**/*"], - "references": [{ "path": "../../core/tsconfig.json" }] -} diff --git a/src/plugins/share/common/anonymous_access/index.mock.ts b/src/plugins/share/common/anonymous_access/index.mock.ts new file mode 100644 index 00000000000000..9b5a8500dff5a4 --- /dev/null +++ b/src/plugins/share/common/anonymous_access/index.mock.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 type { AnonymousAccessServiceContract } from './types'; + +export const anonymousAccessMock = { + create: (): jest.Mocked => ({ + getState: jest.fn(), + getCapabilities: jest.fn(), + }), +}; diff --git a/src/plugins/share/common/anonymous_access/index.ts b/src/plugins/share/common/anonymous_access/index.ts new file mode 100644 index 00000000000000..d9746fdd247b52 --- /dev/null +++ b/src/plugins/share/common/anonymous_access/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { AnonymousAccessServiceContract, AnonymousAccessState } from './types'; diff --git a/src/plugins/share/common/anonymous_access/types.ts b/src/plugins/share/common/anonymous_access/types.ts new file mode 100644 index 00000000000000..7ab731dfabaaa5 --- /dev/null +++ b/src/plugins/share/common/anonymous_access/types.ts @@ -0,0 +1,39 @@ +/* + * 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 { Capabilities } from 'src/core/public'; + +/** + * The contract that is used to check anonymous access for the purposes of sharing public links. The implementation is intended to be + * provided by the security plugin. + */ +export interface AnonymousAccessServiceContract { + /** + * This function returns the current state of anonymous access. + */ + getState: () => Promise; + /** + * This function returns the capabilities of the anonymous access user. + */ + getCapabilities: () => Promise; +} + +/** + * The state of anonymous access. + */ +export interface AnonymousAccessState { + /** + * Whether anonymous access is enabled or not. + */ + isEnabled: boolean; + /** + * If anonymous access is enabled, this reflects what URL parameters need to be added to a Kibana link to make it publicly accessible. + * Note that if anonymous access is the only authentication method, this will be null. + */ + accessURLParameters: Record | null; +} diff --git a/src/plugins/share/common/index.ts b/src/plugins/share/common/index.ts index 69898f3d72019a..992ec2447855f2 100644 --- a/src/plugins/share/common/index.ts +++ b/src/plugins/share/common/index.ts @@ -7,3 +7,4 @@ */ export { LocatorDefinition, LocatorPublic, useLocatorUrl, formatSearchParams } from './url_service'; +export type { AnonymousAccessServiceContract, AnonymousAccessState } from './anonymous_access'; diff --git a/src/plugins/share/kibana.json b/src/plugins/share/kibana.json index 2616b299da28d8..2e34da1da0287c 100644 --- a/src/plugins/share/kibana.json +++ b/src/plugins/share/kibana.json @@ -9,5 +9,5 @@ }, "description": "Adds URL Service and sharing capabilities to Kibana", "requiredBundles": ["kibanaUtils"], - "optionalPlugins": ["securityOss"] + "optionalPlugins": [] } diff --git a/src/plugins/share/public/components/share_context_menu.tsx b/src/plugins/share/public/components/share_context_menu.tsx index 201bc0c665dd33..8e931c5c579fa6 100644 --- a/src/plugins/share/public/components/share_context_menu.tsx +++ b/src/plugins/share/public/components/share_context_menu.tsx @@ -17,7 +17,7 @@ import type { Capabilities } from 'src/core/public'; import { UrlPanelContent } from './url_panel_content'; import { ShareMenuItem, ShareContextMenuPanelItem, UrlParamExtension } from '../types'; -import type { SecurityOssPluginStart } from '../../../security_oss/public'; +import { AnonymousAccessServiceContract } from '../../common/anonymous_access'; interface Props { allowEmbed: boolean; @@ -31,7 +31,7 @@ interface Props { basePath: string; post: HttpStart['post']; embedUrlParamExtensions?: UrlParamExtension[]; - anonymousAccess?: SecurityOssPluginStart['anonymousAccess']; + anonymousAccess?: AnonymousAccessServiceContract; showPublicUrlSwitch?: (anonymousUserCapabilities: Capabilities) => boolean; } diff --git a/src/plugins/share/public/components/url_panel_content.tsx b/src/plugins/share/public/components/url_panel_content.tsx index 80c29f10b57d50..4fdf6f9b830929 100644 --- a/src/plugins/share/public/components/url_panel_content.tsx +++ b/src/plugins/share/public/components/url_panel_content.tsx @@ -32,7 +32,10 @@ import type { Capabilities } from 'src/core/public'; import { shortenUrl } from '../lib/url_shortener'; import { UrlParamExtension } from '../types'; -import type { SecurityOssPluginStart } from '../../../security_oss/public'; +import { + AnonymousAccessServiceContract, + AnonymousAccessState, +} from '../../common/anonymous_access'; interface Props { allowShortUrl: boolean; @@ -43,7 +46,7 @@ interface Props { basePath: string; post: HttpStart['post']; urlParamExtensions?: UrlParamExtension[]; - anonymousAccess?: SecurityOssPluginStart['anonymousAccess']; + anonymousAccess?: AnonymousAccessServiceContract; showPublicUrlSwitch?: (anonymousUserCapabilities: Capabilities) => boolean; } @@ -66,7 +69,7 @@ interface State { url?: string; shortUrlErrorMsg?: string; urlParams?: UrlParams; - anonymousAccessParameters: Record | null; + anonymousAccessParameters: AnonymousAccessState['accessURLParameters']; showPublicUrlSwitch: boolean; } @@ -104,8 +107,8 @@ export class UrlPanelContent extends Component { if (this.props.anonymousAccess) { (async () => { - const anonymousAccessParameters = - await this.props.anonymousAccess!.getAccessURLParameters(); + const { accessURLParameters: anonymousAccessParameters } = + await this.props.anonymousAccess!.getState(); if (!this.mounted) { return; diff --git a/src/plugins/share/public/mocks.ts b/src/plugins/share/public/mocks.ts index 4b8a3b915d13da..73df7257290f09 100644 --- a/src/plugins/share/public/mocks.ts +++ b/src/plugins/share/public/mocks.ts @@ -44,6 +44,7 @@ const createSetupContract = (): Setup => { }, url, navigate: jest.fn(), + setAnonymousAccessServiceProvider: jest.fn(), }; return setupContract; }; diff --git a/src/plugins/share/public/plugin.test.ts b/src/plugins/share/public/plugin.test.ts index c08d13d70d1e29..7d5da45f768d52 100644 --- a/src/plugins/share/public/plugin.test.ts +++ b/src/plugins/share/public/plugin.test.ts @@ -10,7 +10,7 @@ import { registryMock, managerMock } from './plugin.test.mocks'; import { SharePlugin } from './plugin'; import { CoreStart } from 'kibana/public'; import { coreMock } from '../../../core/public/mocks'; -import { mockSecurityOssPlugin } from '../../security_oss/public/mocks'; +import { anonymousAccessMock } from '../common/anonymous_access/index.mock'; describe('SharePlugin', () => { beforeEach(() => { @@ -22,12 +22,8 @@ describe('SharePlugin', () => { describe('setup', () => { test('wires up and returns registry', async () => { const coreSetup = coreMock.createSetup(); - const plugins = { - securityOss: mockSecurityOssPlugin.createSetup(), - }; const setup = await new SharePlugin(coreMock.createPluginInitializerContext()).setup( - coreSetup, - plugins + coreSetup ); expect(registryMock.setup).toHaveBeenCalledWith(); expect(setup.register).toBeDefined(); @@ -35,10 +31,7 @@ describe('SharePlugin', () => { test('registers redirect app', async () => { const coreSetup = coreMock.createSetup(); - const plugins = { - securityOss: mockSecurityOssPlugin.createSetup(), - }; - await new SharePlugin(coreMock.createPluginInitializerContext()).setup(coreSetup, plugins); + await new SharePlugin(coreMock.createPluginInitializerContext()).setup(coreSetup); expect(coreSetup.application.register).toHaveBeenCalledWith( expect.objectContaining({ id: 'short_url_redirect', @@ -50,22 +43,34 @@ describe('SharePlugin', () => { describe('start', () => { test('wires up and returns show function, but not registry', async () => { const coreSetup = coreMock.createSetup(); - const pluginsSetup = { - securityOss: mockSecurityOssPlugin.createSetup(), - }; const service = new SharePlugin(coreMock.createPluginInitializerContext()); - await service.setup(coreSetup, pluginsSetup); - const pluginsStart = { - securityOss: mockSecurityOssPlugin.createStart(), - }; - const start = await service.start({} as CoreStart, pluginsStart); + await service.setup(coreSetup); + const start = await service.start({} as CoreStart); expect(registryMock.start).toHaveBeenCalled(); expect(managerMock.start).toHaveBeenCalledWith( expect.anything(), expect.objectContaining({ getShareMenuItems: expect.any(Function), }), - expect.anything() + undefined + ); + expect(start.toggleShareContextMenu).toBeDefined(); + }); + + test('passes anonymous access service provider to the share menu manager when it is available', async () => { + const coreSetup = coreMock.createSetup(); + const service = new SharePlugin(coreMock.createPluginInitializerContext()); + const setup = await service.setup(coreSetup); + const anonymousAccessServiceProvider = () => anonymousAccessMock.create(); + setup.setAnonymousAccessServiceProvider(anonymousAccessServiceProvider); + const start = await service.start({} as CoreStart); + expect(registryMock.start).toHaveBeenCalled(); + expect(managerMock.start).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ + getShareMenuItems: expect.any(Function), + }), + anonymousAccessServiceProvider ); expect(start.toggleShareContextMenu).toBeDefined(); }); diff --git a/src/plugins/share/public/plugin.ts b/src/plugins/share/public/plugin.ts index 26b5c7e753a2e2..103fbb50bb95f5 100644 --- a/src/plugins/share/public/plugin.ts +++ b/src/plugins/share/public/plugin.ts @@ -10,7 +10,6 @@ import './index.scss'; import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/public'; import { ShareMenuManager, ShareMenuManagerStart } from './services'; -import type { SecurityOssPluginSetup, SecurityOssPluginStart } from '../../security_oss/public'; import { ShareMenuRegistry, ShareMenuRegistrySetup } from './services'; import { createShortUrlRedirectApp } from './services/short_url_redirect_app'; import { @@ -22,14 +21,7 @@ import { UrlService } from '../common/url_service'; import { RedirectManager } from './url_service'; import type { RedirectOptions } from '../common/url_service/locators/redirect'; import { LegacyShortUrlLocatorDefinition } from '../common/url_service/locators/legacy_short_url_locator'; - -export interface ShareSetupDependencies { - securityOss?: SecurityOssPluginSetup; -} - -export interface ShareStartDependencies { - securityOss?: SecurityOssPluginStart; -} +import { AnonymousAccessServiceContract } from '../common'; /** @public */ export type SharePluginSetup = ShareMenuRegistrySetup & { @@ -50,6 +42,11 @@ export type SharePluginSetup = ShareMenuRegistrySetup & { * the locator, then using the locator to navigate. */ navigate(options: RedirectOptions): void; + + /** + * Sets the provider for the anonymous access service; this is consumed by the Security plugin to avoid a circular dependency. + */ + setAnonymousAccessServiceProvider: (provider: () => AnonymousAccessServiceContract) => void; }; /** @public */ @@ -80,10 +77,11 @@ export class SharePlugin implements Plugin { private redirectManager?: RedirectManager; private url?: UrlService; + private anonymousAccessServiceProvider?: () => AnonymousAccessServiceContract; constructor(private readonly initializerContext: PluginInitializerContext) {} - public setup(core: CoreSetup, plugins: ShareSetupDependencies): SharePluginSetup { + public setup(core: CoreSetup): SharePluginSetup { const { application, http } = core; const { basePath } = http; @@ -138,15 +136,21 @@ export class SharePlugin implements Plugin { urlGenerators: this.urlGeneratorsService.setup(core), url: this.url, navigate: (options: RedirectOptions) => this.redirectManager!.navigate(options), + setAnonymousAccessServiceProvider: (provider: () => AnonymousAccessServiceContract) => { + if (this.anonymousAccessServiceProvider) { + throw new Error('Anonymous Access service provider is already set.'); + } + this.anonymousAccessServiceProvider = provider; + }, }; } - public start(core: CoreStart, plugins: ShareStartDependencies): SharePluginStart { + public start(core: CoreStart): SharePluginStart { return { ...this.shareContextMenu.start( core, this.shareMenuRegistry.start(), - plugins.securityOss?.anonymousAccess + this.anonymousAccessServiceProvider ), urlGenerators: this.urlGeneratorsService.start(core), url: this.url!, diff --git a/src/plugins/share/public/services/share_menu_manager.tsx b/src/plugins/share/public/services/share_menu_manager.tsx index 144f65f9011dcd..c7251ee4dd414d 100644 --- a/src/plugins/share/public/services/share_menu_manager.tsx +++ b/src/plugins/share/public/services/share_menu_manager.tsx @@ -15,7 +15,7 @@ import { CoreStart, HttpStart } from 'kibana/public'; import { ShareContextMenu } from '../components/share_context_menu'; import { ShareMenuItem, ShowShareMenuOptions } from '../types'; import { ShareMenuRegistryStart } from './share_menu_registry'; -import type { SecurityOssPluginStart } from '../../../security_oss/public'; +import { AnonymousAccessServiceContract } from '../../common/anonymous_access'; export class ShareMenuManager { private isOpen = false; @@ -25,7 +25,7 @@ export class ShareMenuManager { start( core: CoreStart, shareRegistry: ShareMenuRegistryStart, - anonymousAccess?: SecurityOssPluginStart['anonymousAccess'] + anonymousAccessServiceProvider?: () => AnonymousAccessServiceContract ) { return { /** @@ -35,6 +35,7 @@ export class ShareMenuManager { */ toggleShareContextMenu: (options: ShowShareMenuOptions) => { const menuItems = shareRegistry.getShareMenuItems({ ...options, onClose: this.onClose }); + const anonymousAccess = anonymousAccessServiceProvider?.(); this.toggleShareContextMenu({ ...options, menuItems, @@ -69,7 +70,7 @@ export class ShareMenuManager { menuItems: ShareMenuItem[]; post: HttpStart['post']; basePath: string; - anonymousAccess?: SecurityOssPluginStart['anonymousAccess']; + anonymousAccess: AnonymousAccessServiceContract | undefined; }) { if (this.isOpen) { this.onClose(); diff --git a/src/plugins/share/tsconfig.json b/src/plugins/share/tsconfig.json index c6afc06bc61c2d..1f9c438f03fc40 100644 --- a/src/plugins/share/tsconfig.json +++ b/src/plugins/share/tsconfig.json @@ -10,6 +10,5 @@ "references": [ { "path": "../../core/tsconfig.json" }, { "path": "../kibana_utils/tsconfig.json" }, - { "path": "../security_oss/tsconfig.json" } ] } diff --git a/src/plugins/vis_types/metric/kibana.json b/src/plugins/vis_types/metric/kibana.json index 950abea1c5a9b2..ab69f78430338e 100644 --- a/src/plugins/vis_types/metric/kibana.json +++ b/src/plugins/vis_types/metric/kibana.json @@ -5,7 +5,7 @@ "server": true, "ui": true, "requiredPlugins": ["data", "visualizations", "charts", "expressions"], - "requiredBundles": ["kibanaUtils", "visDefaultEditor"], + "requiredBundles": ["visDefaultEditor"], "owner": { "name": "Vis Editors", "githubTeam": "kibana-vis-editors" diff --git a/src/plugins/security_oss/public/mocks.ts b/src/plugins/vis_types/metric/public/components/index.ts similarity index 86% rename from src/plugins/security_oss/public/mocks.ts rename to src/plugins/vis_types/metric/public/components/index.ts index ee15f57b351cde..41c9bf10e73873 100644 --- a/src/plugins/security_oss/public/mocks.ts +++ b/src/plugins/vis_types/metric/public/components/index.ts @@ -6,4 +6,4 @@ * Side Public License, v 1. */ -export { mockSecurityOssPlugin } from './plugin.mock'; +export { MetricVisOptions } from './metric_vis_options'; diff --git a/src/plugins/vis_types/metric/public/metric_vis_type.ts b/src/plugins/vis_types/metric/public/metric_vis_type.ts index 9fc3856ba0edf1..ccacd4eae6bf93 100644 --- a/src/plugins/vis_types/metric/public/metric_vis_type.ts +++ b/src/plugins/vis_types/metric/public/metric_vis_type.ts @@ -7,7 +7,7 @@ */ import { i18n } from '@kbn/i18n'; -import { MetricVisOptions } from './components/metric_vis_options'; +import { MetricVisOptions } from './components'; import { ColorSchemas, ColorMode } from '../../../charts/public'; import { VisTypeDefinition } from '../../../visualizations/public'; import { AggGroupNames } from '../../../data/public'; diff --git a/src/plugins/vis_types/metric/public/plugin.ts b/src/plugins/vis_types/metric/public/plugin.ts index 205c02d8e9c3be..a88bbc8e5f2e9a 100644 --- a/src/plugins/vis_types/metric/public/plugin.ts +++ b/src/plugins/vis_types/metric/public/plugin.ts @@ -7,27 +7,13 @@ */ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'kibana/public'; -import { Plugin as ExpressionsPublicPlugin } from '../../../expressions/public'; import { VisualizationsSetup } from '../../../visualizations/public'; - -import { createMetricVisFn } from './metric_vis_fn'; import { createMetricVisTypeDefinition } from './metric_vis_type'; -import { ChartsPluginSetup } from '../../../charts/public'; -import { DataPublicPluginStart } from '../../../data/public'; -import { setFormatService } from './services'; import { ConfigSchema } from '../config'; -import { metricVisRenderer } from './metric_vis_renderer'; /** @internal */ export interface MetricVisPluginSetupDependencies { - expressions: ReturnType; visualizations: VisualizationsSetup; - charts: ChartsPluginSetup; -} - -/** @internal */ -export interface MetricVisPluginStartDependencies { - data: DataPublicPluginStart; } /** @internal */ @@ -38,16 +24,9 @@ export class MetricVisPlugin implements Plugin { this.initializerContext = initializerContext; } - public setup( - core: CoreSetup, - { expressions, visualizations, charts }: MetricVisPluginSetupDependencies - ) { - expressions.registerFunction(createMetricVisFn); - expressions.registerRenderer(metricVisRenderer); + public setup(core: CoreSetup, { visualizations }: MetricVisPluginSetupDependencies) { visualizations.createBaseVisualization(createMetricVisTypeDefinition()); } - public start(core: CoreStart, { data }: MetricVisPluginStartDependencies) { - setFormatService(data.fieldFormats); - } + public start(core: CoreStart) {} } diff --git a/src/plugins/vis_types/metric/public/services.ts b/src/plugins/vis_types/metric/public/services.ts deleted file mode 100644 index e705513675e71a..00000000000000 --- a/src/plugins/vis_types/metric/public/services.ts +++ /dev/null @@ -1,14 +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 { createGetterSetter } from '../../../kibana_utils/common'; -import { DataPublicPluginStart } from '../../../data/public'; - -export const [getFormatService, setFormatService] = createGetterSetter< - DataPublicPluginStart['fieldFormats'] ->('metric data.fieldFormats'); diff --git a/src/plugins/vis_types/metric/public/to_ast.ts b/src/plugins/vis_types/metric/public/to_ast.ts index 10c782c9a50fb4..1e23a10dd7608b 100644 --- a/src/plugins/vis_types/metric/public/to_ast.ts +++ b/src/plugins/vis_types/metric/public/to_ast.ts @@ -9,7 +9,6 @@ import { get } from 'lodash'; import { getVisSchemas, SchemaConfig, VisToExpressionAst } from '../../../visualizations/public'; import { buildExpression, buildExpressionFunction } from '../../../expressions/public'; -import { MetricVisExpressionFunctionDefinition } from './metric_vis_fn'; import { EsaggsExpressionFunctionDefinition, IndexPatternLoadExpressionFunctionDefinition, @@ -63,8 +62,7 @@ export const toExpressionAst: VisToExpressionAst = (vis, params) => { }); } - // @ts-expect-error - const metricVis = buildExpressionFunction('metricVis', { + const metricVis = buildExpressionFunction('metricVis', { percentageMode, colorSchema, colorMode: metricColorMode, diff --git a/src/plugins/vis_types/metric/public/types.ts b/src/plugins/vis_types/metric/public/types.ts index 8e86c0217bba6e..98065348fa91db 100644 --- a/src/plugins/vis_types/metric/public/types.ts +++ b/src/plugins/vis_types/metric/public/types.ts @@ -36,12 +36,3 @@ export interface VisParams { metric: MetricVisParam; type: typeof visType; } - -export interface MetricVisMetric { - value: any; - label: string; - color?: string; - bgColor?: string; - lightText: boolean; - rowIndex: number; -} diff --git a/src/plugins/vis_types/metric/tsconfig.json b/src/plugins/vis_types/metric/tsconfig.json index e8c878425ff706..e8e2bb0573014d 100644 --- a/src/plugins/vis_types/metric/tsconfig.json +++ b/src/plugins/vis_types/metric/tsconfig.json @@ -13,8 +13,6 @@ { "path": "../../visualizations/tsconfig.json" }, { "path": "../../charts/tsconfig.json" }, { "path": "../../expressions/tsconfig.json" }, - { "path": "../../kibana_utils/tsconfig.json" }, - { "path": "../../vis_default_editor/tsconfig.json" }, - { "path": "../../field_formats/tsconfig.json" } + { "path": "../../vis_default_editor/tsconfig.json" } ] } diff --git a/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx index d28e2c5e0fb9a7..1029ac67cc43ce 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx @@ -33,28 +33,22 @@ export interface IndexPatternSelectProps { | null; } -const queryAllIndicesHelpText = ( - *, - }} - /> +const defaultIndexPatternHelpText = i18n.translate( + 'visTypeTimeseries.indexPatternSelect.defaultIndexPatternText', + { + defaultMessage: 'Default index pattern is used.', + } ); -const getIndexPatternHelpText = (useKibanaIndices: boolean) => ( - +const queryAllIndexesHelpText = i18n.translate( + 'visTypeTimeseries.indexPatternSelect.queryAllIndexesText', + { + defaultMessage: 'To query all indexes use *', + } ); const indexPatternLabel = i18n.translate('visTypeTimeseries.indexPatternSelect.label', { - defaultMessage: 'Data view', + defaultMessage: 'Index pattern', }); export const IndexPatternSelect = ({ @@ -109,14 +103,17 @@ export const IndexPatternSelect = ({ diff --git a/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/switch_mode_popover.tsx b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/switch_mode_popover.tsx index 16eeaff30c2080..f33f51f60d0486 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/switch_mode_popover.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/switch_mode_popover.tsx @@ -79,7 +79,7 @@ export const SwitchModePopover = ({ onModeChange, useKibanaIndices }: PopoverPro aria-label={i18n.translate( 'visTypeTimeseries.indexPatternSelect.switchModePopover.areaLabel', { - defaultMessage: 'Configure data view selection mode', + defaultMessage: 'Configure index pattern selection mode', } )} onClick={onButtonClick} @@ -97,13 +97,14 @@ export const SwitchModePopover = ({ onModeChange, useKibanaIndices }: PopoverPro > {i18n.translate('visTypeTimeseries.indexPatternSelect.switchModePopover.title', { - defaultMessage: 'Data view mode', + defaultMessage: 'Index pattern selection mode', })} { { } iconType="cheer" @@ -42,13 +42,13 @@ export const UseIndexPatternModeCallout = () => { >

@@ -59,7 +59,7 @@ export const UseIndexPatternModeCallout = () => { diff --git a/src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/config.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/config.js index 208f9af9bb2503..4257c35a6d4c20 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/config.js +++ b/src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/config.js @@ -538,8 +538,8 @@ export const TimeseriesConfig = injectI18n(function (props) { { type: 'index-pattern', getIconForSavedObject: () => 'indexPatternApp', name: i18n.translate( - 'visualizations.newVisWizard.searchSelection.savedObjectType.dataView', + 'visualizations.newVisWizard.searchSelection.savedObjectType.indexPattern', { - defaultMessage: 'Data view', + defaultMessage: 'Index pattern', } ), }, diff --git a/test/interpreter_functional/screenshots/baseline/metric_all_data.png b/test/interpreter_functional/screenshots/baseline/metric_all_data.png index 66357a371a5be9..18dca6c2c39c2a 100644 Binary files a/test/interpreter_functional/screenshots/baseline/metric_all_data.png and b/test/interpreter_functional/screenshots/baseline/metric_all_data.png differ diff --git a/test/interpreter_functional/screenshots/baseline/metric_empty_data.png b/test/interpreter_functional/screenshots/baseline/metric_empty_data.png index 06cd781415ab05..db1dda5083de2d 100644 Binary files a/test/interpreter_functional/screenshots/baseline/metric_empty_data.png and b/test/interpreter_functional/screenshots/baseline/metric_empty_data.png differ diff --git a/test/interpreter_functional/screenshots/baseline/metric_multi_metric_data.png b/test/interpreter_functional/screenshots/baseline/metric_multi_metric_data.png index 5888fba713befb..1e859442501563 100644 Binary files a/test/interpreter_functional/screenshots/baseline/metric_multi_metric_data.png and b/test/interpreter_functional/screenshots/baseline/metric_multi_metric_data.png differ diff --git a/test/interpreter_functional/screenshots/baseline/metric_percentage_mode.png b/test/interpreter_functional/screenshots/baseline/metric_percentage_mode.png index 8a5fd9d7a72856..bcf33d9171193e 100644 Binary files a/test/interpreter_functional/screenshots/baseline/metric_percentage_mode.png and b/test/interpreter_functional/screenshots/baseline/metric_percentage_mode.png differ diff --git a/test/interpreter_functional/screenshots/baseline/metric_single_metric_data.png b/test/interpreter_functional/screenshots/baseline/metric_single_metric_data.png index 315653ee2b9401..a82654240e374d 100644 Binary files a/test/interpreter_functional/screenshots/baseline/metric_single_metric_data.png and b/test/interpreter_functional/screenshots/baseline/metric_single_metric_data.png differ diff --git a/test/interpreter_functional/snapshots/baseline/combined_test3.json b/test/interpreter_functional/snapshots/baseline/combined_test3.json index 64b1052552c8ff..107d3fcbc5c542 100644 --- a/test/interpreter_functional/snapshots/baseline/combined_test3.json +++ b/test/interpreter_functional/snapshots/baseline/combined_test3.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/final_output_test.json b/test/interpreter_functional/snapshots/baseline/final_output_test.json index 64b1052552c8ff..107d3fcbc5c542 100644 --- a/test/interpreter_functional/snapshots/baseline/final_output_test.json +++ b/test/interpreter_functional/snapshots/baseline/final_output_test.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_all_data.json b/test/interpreter_functional/snapshots/baseline/metric_all_data.json index 0e1e5a723373f8..9c10b53ce86049 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_all_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_all_data.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_empty_data.json b/test/interpreter_functional/snapshots/baseline/metric_empty_data.json index c318121535c8f1..6fa08239f422d2 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_empty_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_empty_data.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json b/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json index fc8622a818decb..4410447d2bb20a 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json b/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json index 95c011f9259b9f..2abb3070c3d054 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json +++ b/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":1000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":true,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":1000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":true,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json b/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json index f4a8cd1f14e18a..cce892a2f8c6fc 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/partial_test_2.json b/test/interpreter_functional/snapshots/baseline/partial_test_2.json index 64b1052552c8ff..107d3fcbc5c542 100644 --- a/test/interpreter_functional/snapshots/baseline/partial_test_2.json +++ b/test/interpreter_functional/snapshots/baseline/partial_test_2.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/step_output_test3.json b/test/interpreter_functional/snapshots/baseline/step_output_test3.json index 64b1052552c8ff..107d3fcbc5c542 100644 --- a/test/interpreter_functional/snapshots/baseline/step_output_test3.json +++ b/test/interpreter_functional/snapshots/baseline/step_output_test3.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/combined_test3.json b/test/interpreter_functional/snapshots/session/combined_test3.json index 64b1052552c8ff..107d3fcbc5c542 100644 --- a/test/interpreter_functional/snapshots/session/combined_test3.json +++ b/test/interpreter_functional/snapshots/session/combined_test3.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/final_output_test.json b/test/interpreter_functional/snapshots/session/final_output_test.json index 64b1052552c8ff..107d3fcbc5c542 100644 --- a/test/interpreter_functional/snapshots/session/final_output_test.json +++ b/test/interpreter_functional/snapshots/session/final_output_test.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_all_data.json b/test/interpreter_functional/snapshots/session/metric_all_data.json index 0e1e5a723373f8..9c10b53ce86049 100644 --- a/test/interpreter_functional/snapshots/session/metric_all_data.json +++ b/test/interpreter_functional/snapshots/session/metric_all_data.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_empty_data.json b/test/interpreter_functional/snapshots/session/metric_empty_data.json index c318121535c8f1..6fa08239f422d2 100644 --- a/test/interpreter_functional/snapshots/session/metric_empty_data.json +++ b/test/interpreter_functional/snapshots/session/metric_empty_data.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json b/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json index fc8622a818decb..4410447d2bb20a 100644 --- a/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json +++ b/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_percentage_mode.json b/test/interpreter_functional/snapshots/session/metric_percentage_mode.json index 95c011f9259b9f..2abb3070c3d054 100644 --- a/test/interpreter_functional/snapshots/session/metric_percentage_mode.json +++ b/test/interpreter_functional/snapshots/session/metric_percentage_mode.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":1000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":true,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":1000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":true,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_single_metric_data.json b/test/interpreter_functional/snapshots/session/metric_single_metric_data.json index f4a8cd1f14e18a..cce892a2f8c6fc 100644 --- a/test/interpreter_functional/snapshots/session/metric_single_metric_data.json +++ b/test/interpreter_functional/snapshots/session/metric_single_metric_data.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/partial_test_2.json b/test/interpreter_functional/snapshots/session/partial_test_2.json index 64b1052552c8ff..107d3fcbc5c542 100644 --- a/test/interpreter_functional/snapshots/session/partial_test_2.json +++ b/test/interpreter_functional/snapshots/session/partial_test_2.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/step_output_test3.json b/test/interpreter_functional/snapshots/session/step_output_test3.json index 64b1052552c8ff..107d3fcbc5c542 100644 --- a/test/interpreter_functional/snapshots/session/step_output_test3.json +++ b/test/interpreter_functional/snapshots/session/step_output_test3.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/security_functional/config.ts b/test/security_functional/config.ts deleted file mode 100644 index b01f27b4cb7d6c..00000000000000 --- a/test/security_functional/config.ts +++ /dev/null @@ -1,40 +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 path from 'path'; -import { FtrConfigProviderContext } from '@kbn/test'; - -export default async function ({ readConfigFile }: FtrConfigProviderContext) { - const functionalConfig = await readConfigFile(require.resolve('../functional/config')); - - return { - testFiles: [require.resolve('./index.ts')], - services: functionalConfig.get('services'), - pageObjects: functionalConfig.get('pageObjects'), - servers: functionalConfig.get('servers'), - esTestCluster: functionalConfig.get('esTestCluster'), - apps: {}, - snapshots: { - directory: path.resolve(__dirname, 'snapshots'), - }, - junit: { - reportName: 'Security OSS Functional Tests', - }, - kbnTestServer: { - ...functionalConfig.get('kbnTestServer'), - serverArgs: [ - ...functionalConfig - .get('kbnTestServer.serverArgs') - .filter((arg: string) => !arg.startsWith('--security.showInsecureClusterWarning')), - '--security.showInsecureClusterWarning=true', - // Required to load new platform plugins via `--plugin-path` flag. - '--env.name=development', - ], - }, - }; -} diff --git a/test/security_functional/index.ts b/test/security_functional/index.ts deleted file mode 100644 index 0d067c58b84b00..00000000000000 --- a/test/security_functional/index.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 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 { FtrProviderContext } from '../functional/ftr_provider_context'; - -// eslint-disable-next-line import/no-default-export -export default function ({ loadTestFile }: FtrProviderContext) { - describe('Security OSS', function () { - this.tags(['skipCloud', 'ciGroup2']); - loadTestFile(require.resolve('./insecure_cluster_warning')); - }); -} diff --git a/test/security_functional/insecure_cluster_warning.ts b/test/security_functional/insecure_cluster_warning.ts deleted file mode 100644 index 238643e573540b..00000000000000 --- a/test/security_functional/insecure_cluster_warning.ts +++ /dev/null @@ -1,77 +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 { FtrProviderContext } from 'test/functional/ftr_provider_context'; - -// eslint-disable-next-line import/no-default-export -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const pageObjects = getPageObjects(['common']); - const testSubjects = getService('testSubjects'); - const browser = getService('browser'); - const esArchiver = getService('esArchiver'); - - describe('Insecure Cluster Warning', () => { - before(async () => { - await pageObjects.common.navigateToApp('home'); - await browser.setLocalStorageItem('insecureClusterWarningVisibility', ''); - // starting without user data - await esArchiver.unload('test/functional/fixtures/es_archiver/hamlet'); - }); - - after(async () => { - await esArchiver.unload('test/functional/fixtures/es_archiver/hamlet'); - }); - - describe('without user data', () => { - before(async () => { - await browser.setLocalStorageItem('insecureClusterWarningVisibility', ''); - await esArchiver.unload('test/functional/fixtures/es_archiver/hamlet'); - await esArchiver.emptyKibanaIndex(); - }); - - it('should not warn when the cluster contains no user data', async () => { - await browser.setLocalStorageItem( - 'insecureClusterWarningVisibility', - JSON.stringify({ show: false }) - ); - await pageObjects.common.navigateToApp('home'); - await testSubjects.missingOrFail('insecureClusterDefaultAlertText'); - }); - }); - - describe('with user data', () => { - before(async () => { - await pageObjects.common.navigateToApp('home'); - await browser.setLocalStorageItem('insecureClusterWarningVisibility', ''); - await esArchiver.load('test/functional/fixtures/es_archiver/hamlet'); - }); - - after(async () => { - await esArchiver.unload('test/functional/fixtures/es_archiver/hamlet'); - }); - - it('should warn about an insecure cluster, and hide when dismissed', async () => { - await pageObjects.common.navigateToApp('home'); - await testSubjects.existOrFail('insecureClusterDefaultAlertText'); - - await testSubjects.click('defaultDismissAlertButton'); - - await testSubjects.missingOrFail('insecureClusterDefaultAlertText'); - }); - - it('should not warn when local storage is configured to hide', async () => { - await browser.setLocalStorageItem( - 'insecureClusterWarningVisibility', - JSON.stringify({ show: false }) - ); - await pageObjects.common.navigateToApp('home'); - await testSubjects.missingOrFail('insecureClusterDefaultAlertText'); - }); - }); - }); -} diff --git a/utilities/templates/visual_regression_gallery.handlebars b/utilities/templates/visual_regression_gallery.handlebars deleted file mode 100644 index 60817dec5fcf22..00000000000000 --- a/utilities/templates/visual_regression_gallery.handlebars +++ /dev/null @@ -1,297 +0,0 @@ - - - - Kibana Visual Regression Gallery - - - - - - - - -

- Kibana Visual Regression Gallery -
- -
- {{branch}} - {{date}} -
- - {{#each comparisons as |comparison|}} -
- -
- ({{comparison.percentage}}%) {{comparison.name}} -
- -
-
Diff
- -
- Baseline -
-
- -
- -
- -
- - - - - -
- -
-
-
- {{/each}} - - - - - diff --git a/utilities/visual_regression.js b/utilities/visual_regression.js deleted file mode 100644 index fa4d48a2280d5c..00000000000000 --- a/utilities/visual_regression.js +++ /dev/null @@ -1,141 +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 bluebird, { promisify } from 'bluebird'; -import Handlebars from 'handlebars'; -import fs from 'fs'; -import path from 'path'; -import { PNG } from 'pngjs'; -import pixelmatch from 'pixelmatch'; -import moment from 'moment'; -import SimpleGit from 'simple-git'; - -const readDirAsync = promisify(fs.readdir); -const readFileAsync = promisify(fs.readFile); -const writeFileAsync = promisify(fs.writeFile); - -Handlebars.registerHelper('lte', function lessThanEquals(value, threshold, options) { - if (value <= threshold) { - return options.fn(this); - } - return options.inverse(this); -}); - -Handlebars.registerHelper('gte', function greaterThanEquals(value, threshold, options) { - if (value >= threshold) { - return options.fn(this); - } - return options.inverse(this); -}); - -async function buildGallery(comparisons) { - const simpleGit = new SimpleGit(); - const asyncBranch = promisify(simpleGit.branch, simpleGit); - const branch = await asyncBranch(); - - const template = Handlebars.compile( - await readFileAsync( - path.resolve('./utilities/templates/visual_regression_gallery.handlebars'), - 'utf8' - ), - { knownHelpersOnly: true } - ); - - const html = template({ - date: moment().format('MMMM Do YYYY, h:mm:ss a'), - branch: branch.current, - hiddenThreshold: 0, - warningThreshold: 0.03, - comparisons, - }); - - return writeFileAsync( - path.resolve('./test/functional/screenshots/visual_regression_gallery.html'), - html - ); -} - -async function compareScreenshots() { - const SCREENSHOTS_DIR = 'test/functional/screenshots'; - const BASELINE_SCREENSHOTS_DIR = path.resolve(SCREENSHOTS_DIR, 'baseline'); - const DIFF_SCREENSHOTS_DIR = path.resolve(SCREENSHOTS_DIR, 'diff'); - const SESSION_SCREENSHOTS_DIR = path.resolve(SCREENSHOTS_DIR, 'session'); - - // We don't need to create the baseline dir because it's committed. - fs.mkdirSync(DIFF_SCREENSHOTS_DIR, { recursive: true }); - fs.mkdirSync(SESSION_SCREENSHOTS_DIR, { recursive: true }); - const files = await readDirAsync(SESSION_SCREENSHOTS_DIR); - const screenshots = files.filter((file) => file.indexOf('.png') !== -1); - - // We'll use this data to build a screenshot gallery in HTML. - return await bluebird.map(screenshots, async (screenshot) => { - // We're going to load image data and cache it in this object. - const comparison = { - name: screenshot, - change: undefined, - percentage: undefined, - imageData: { - session: undefined, - baseline: undefined, - diff: undefined, - }, - }; - - const sessionImagePath = path.resolve(SESSION_SCREENSHOTS_DIR, screenshot); - - const baselineImagePath = path.resolve(BASELINE_SCREENSHOTS_DIR, screenshot); - - const diffImagePath = path.resolve(DIFF_SCREENSHOTS_DIR, screenshot); - - const sessionImage = PNG.sync.read(await readFileAsync(sessionImagePath)); - const baselineImage = PNG.sync.read(await readFileAsync(baselineImagePath)); - const { width, height } = sessionImage; - const diff = new PNG({ width, height }); - - const numDiffPixels = pixelmatch( - sessionImage.data, - baselineImage.data, - diff.data, - width, - height, - { threshold: 0 } - ); - - await writeFileAsync(diffImagePath, PNG.sync.write(diff)); - - const change = numDiffPixels / (width * height); - const changePercentage = (change * 100).toFixed(2); - console.log(`(${changePercentage}%) ${screenshot}`); - comparison.percentage = changePercentage; - comparison.change = change; - - // Once the images have been diffed, we can load and store the image data. - comparison.imageData.session = await readFileAsync(sessionImagePath, 'base64'); - - comparison.imageData.baseline = await readFileAsync(baselineImagePath, 'base64'); - - comparison.imageData.diff = await readFileAsync(diffImagePath, 'base64'); - - return comparison; - }); -} - -export function run(done) { - compareScreenshots().then( - (screenshotComparisons) => { - // Once all of the data has been loaded, we can build the gallery. - buildGallery(screenshotComparisons).then(() => { - done(); - }); - }, - (error) => { - console.error(error); - done(false); - } - ); -} diff --git a/vars/tasks.groovy b/vars/tasks.groovy index 5c8f133331e55b..1842e278282b15 100644 --- a/vars/tasks.groovy +++ b/vars/tasks.groovy @@ -146,14 +146,13 @@ def functionalXpack(Map params = [:]) { } } - //temporarily disable apm e2e test since it's breaking due to a version upgrade. - // whenChanged([ - // 'x-pack/plugins/apm/', - // ]) { - // if (githubPr.isPr()) { - // task(kibanaPipeline.functionalTestProcess('xpack-APMCypress', './test/scripts/jenkins_apm_cypress.sh')) - // } - // } + whenChanged([ + 'x-pack/plugins/apm/', + ]) { + if (githubPr.isPr()) { + task(kibanaPipeline.functionalTestProcess('xpack-APMCypress', './test/scripts/jenkins_apm_cypress.sh')) + } + } whenChanged([ 'x-pack/plugins/uptime/', diff --git a/x-pack/plugins/apm/dev_docs/local_setup.md b/x-pack/plugins/apm/dev_docs/local_setup.md index fd350d81a35af4..eaa99560400e60 100644 --- a/x-pack/plugins/apm/dev_docs/local_setup.md +++ b/x-pack/plugins/apm/dev_docs/local_setup.md @@ -46,4 +46,4 @@ This will create: All APM api endpoints accept `_inspect=true` as a query param that will output all Elasticsearch queries performed in that request. It will be available in the browser response and on localhost it is also available in the Kibana Node.js process output. Example: -`/api/apm/services/my_service?_inspect=true` +`/internal/apm/services/my_service?_inspect=true` diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/no_data_screen.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/no_data_screen.ts index 2d5c2a6f16228b..1e954d9982295a 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/no_data_screen.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/no_data_screen.ts @@ -6,7 +6,7 @@ */ /* eslint-disable @typescript-eslint/naming-convention */ -const apmIndicesSaveURL = '/api/apm/settings/apm-indices/save'; +const apmIndicesSaveURL = '/internal/apm/settings/apm-indices/save'; describe('No data screen', () => { describe('bypass no data screen on settings pages', () => { diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/home.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/home.spec.ts index 679e2934f9c37a..8457282f5c2566 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/home.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/home.spec.ts @@ -17,11 +17,11 @@ const serviceInventoryHref = url.format({ const apisToIntercept = [ { - endpoint: '/api/apm/service?*', + endpoint: '/internal/apm/service?*', name: 'servicesMainStatistics', }, { - endpoint: '/api/apm/services/detailed_statistics?*', + endpoint: '/internal/apm/services/detailed_statistics?*', name: 'servicesDetailedStatistics', }, ]; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/header_filters.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/header_filters.spec.ts index 720e9b4b67e0a2..6950a0bbadb9cd 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/header_filters.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/header_filters.spec.ts @@ -16,43 +16,47 @@ const serviceOverviewHref = url.format({ const apisToIntercept = [ { - endpoint: '/api/apm/services/opbeans-node/transactions/charts/latency?*', + endpoint: + '/internal/apm/services/opbeans-node/transactions/charts/latency?*', name: 'latencyChartRequest', }, { - endpoint: '/api/apm/services/opbeans-node/throughput?*', + endpoint: '/internal/apm/services/opbeans-node/throughput?*', name: 'throughputChartRequest', }, { - endpoint: '/api/apm/services/opbeans-node/transactions/charts/error_rate?*', + endpoint: + '/internal/apm/services/opbeans-node/transactions/charts/error_rate?*', name: 'errorRateChartRequest', }, { endpoint: - '/api/apm/services/opbeans-node/transactions/groups/detailed_statistics?*', + '/internal/apm/services/opbeans-node/transactions/groups/detailed_statistics?*', name: 'transactionGroupsDetailedRequest', }, { endpoint: - '/api/apm/services/opbeans-node/service_overview_instances/detailed_statistics?*', + '/internal/apm/services/opbeans-node/service_overview_instances/detailed_statistics?*', name: 'instancesDetailedRequest', }, { endpoint: - '/api/apm/services/opbeans-node/service_overview_instances/main_statistics?*', + '/internal/apm/services/opbeans-node/service_overview_instances/main_statistics?*', name: 'instancesMainStatisticsRequest', }, { - endpoint: '/api/apm/services/opbeans-node/error_groups/main_statistics?*', + endpoint: + '/internal/apm/services/opbeans-node/error_groups/main_statistics?*', name: 'errorGroupsMainStatisticsRequest', }, { - endpoint: '/api/apm/services/opbeans-node/transaction/charts/breakdown?*', + endpoint: + '/internal/apm/services/opbeans-node/transaction/charts/breakdown?*', name: 'transactonBreakdownRequest', }, { endpoint: - '/api/apm/services/opbeans-node/transactions/groups/main_statistics?*', + '/internal/apm/services/opbeans-node/transactions/groups/main_statistics?*', name: 'transactionsGroupsMainStatisticsRequest', }, ]; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/instances_table.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/instances_table.spec.ts index 7bfa4689db4feb..c7d9fa4e32106c 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/instances_table.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/instances_table.spec.ts @@ -18,17 +18,17 @@ const serviceOverviewHref = url.format({ const apisToIntercept = [ { endpoint: - '/api/apm/services/opbeans-java/service_overview_instances/main_statistics?*', + '/internal/apm/services/opbeans-java/service_overview_instances/main_statistics?*', name: 'instancesMainRequest', }, { endpoint: - '/api/apm/services/opbeans-java/service_overview_instances/detailed_statistics?*', + '/internal/apm/services/opbeans-java/service_overview_instances/detailed_statistics?*', name: 'instancesDetailsRequest', }, { endpoint: - '/api/apm/services/opbeans-java/service_overview_instances/details/31651f3c624b81c55dd4633df0b5b9f9ab06b151121b0404ae796632cd1f87ad?*', + '/internal/apm/services/opbeans-java/service_overview_instances/details/31651f3c624b81c55dd4633df0b5b9f9ab06b151121b0404ae796632cd1f87ad?*', name: 'instanceDetailsRequest', }, ]; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/service_overview.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/service_overview.spec.ts index a0dc7082ca331e..b0cf424b8067e1 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/service_overview.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/service_overview.spec.ts @@ -59,7 +59,7 @@ describe('Service Overview', () => { }); it('hides dependency tab when RUM service', () => { - cy.intercept('GET', '/api/apm/services/opbeans-rum/agent?*').as( + cy.intercept('GET', '/internal/apm/services/opbeans-rum/agent?*').as( 'agentRequest' ); cy.visit( diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/time_comparison.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/time_comparison.spec.ts index 2e05a2c062aaf7..65a82a8ab6bdf1 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/time_comparison.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/time_comparison.spec.ts @@ -18,30 +18,32 @@ const serviceOverviewHref = url.format({ const apisToIntercept = [ { - endpoint: '/api/apm/services/opbeans-java/transactions/charts/latency?*', + endpoint: + '/internal/apm/services/opbeans-java/transactions/charts/latency?*', name: 'latencyChartRequest', }, { - endpoint: '/api/apm/services/opbeans-java/throughput?*', + endpoint: '/internal/apm/services/opbeans-java/throughput?*', name: 'throughputChartRequest', }, { - endpoint: '/api/apm/services/opbeans-java/transactions/charts/error_rate?*', + endpoint: + '/internal/apm/services/opbeans-java/transactions/charts/error_rate?*', name: 'errorRateChartRequest', }, { endpoint: - '/api/apm/services/opbeans-java/transactions/groups/detailed_statistics?*', + '/internal/apm/services/opbeans-java/transactions/groups/detailed_statistics?*', name: 'transactionGroupsDetailedRequest', }, { endpoint: - '/api/apm/services/opbeans-java/error_groups/detailed_statistics?*', + '/internal/apm/services/opbeans-java/error_groups/detailed_statistics?*', name: 'errorGroupsDetailedRequest', }, { endpoint: - '/api/apm/services/opbeans-java/service_overview_instances/detailed_statistics?*', + '/internal/apm/services/opbeans-java/service_overview_instances/detailed_statistics?*', name: 'instancesDetailedRequest', }, ]; diff --git a/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.tsx b/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.tsx index cb7b367fb390b8..eac128a7e88c4d 100644 --- a/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.tsx @@ -61,7 +61,8 @@ export function ErrorCountAlertTrigger(props: Props) { }); if (interval && start && end) { return callApmApi({ - endpoint: 'GET /api/apm/alerts/chart_preview/transaction_error_count', + endpoint: + 'GET /internal/apm/alerts/chart_preview/transaction_error_count', params: { query: { environment: params.environment, diff --git a/x-pack/plugins/apm/public/components/alerting/transaction_duration_alert_trigger/index.tsx b/x-pack/plugins/apm/public/components/alerting/transaction_duration_alert_trigger/index.tsx index 5327eb561bfc61..8957dfc823e44e 100644 --- a/x-pack/plugins/apm/public/components/alerting/transaction_duration_alert_trigger/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/transaction_duration_alert_trigger/index.tsx @@ -99,7 +99,8 @@ export function TransactionDurationAlertTrigger(props: Props) { }); if (interval && start && end) { return callApmApi({ - endpoint: 'GET /api/apm/alerts/chart_preview/transaction_duration', + endpoint: + 'GET /internal/apm/alerts/chart_preview/transaction_duration', params: { query: { aggregationType: params.aggregationType, diff --git a/x-pack/plugins/apm/public/components/alerting/transaction_error_rate_alert_trigger/index.tsx b/x-pack/plugins/apm/public/components/alerting/transaction_error_rate_alert_trigger/index.tsx index 3bad7ae15f658c..ddddc4bbecbad5 100644 --- a/x-pack/plugins/apm/public/components/alerting/transaction_error_rate_alert_trigger/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/transaction_error_rate_alert_trigger/index.tsx @@ -68,7 +68,8 @@ export function TransactionErrorRateAlertTrigger(props: Props) { }); if (interval && start && end) { return callApmApi({ - endpoint: 'GET /api/apm/alerts/chart_preview/transaction_error_rate', + endpoint: + 'GET /internal/apm/alerts/chart_preview/transaction_error_rate', params: { query: { environment: params.environment, diff --git a/x-pack/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx index 2d74187f9d83b9..6685dddd87d7f4 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx @@ -76,7 +76,7 @@ async function saveApmIndices({ apmIndices: Record; }) { await callApmApi({ - endpoint: 'POST /api/apm/settings/apm-indices/save', + endpoint: 'POST /internal/apm/settings/apm-indices/save', signal: null, params: { body: apmIndices, @@ -86,7 +86,8 @@ async function saveApmIndices({ clearCache(); } -type ApiResponse = APIReturnType<`GET /api/apm/settings/apm-index-settings`>; +type ApiResponse = + APIReturnType<`GET /internal/apm/settings/apm-index-settings`>; // avoid infinite loop by initializing the state outside the component const INITIAL_STATE: ApiResponse = { apmIndexSettings: [] }; @@ -103,7 +104,7 @@ export function ApmIndices() { (_callApmApi) => { if (canSave) { return _callApmApi({ - endpoint: `GET /api/apm/settings/apm-index-settings`, + endpoint: `GET /internal/apm/settings/apm-index-settings`, }); } }, diff --git a/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/add_environments.tsx b/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/add_environments.tsx index a60e685eacbde0..b130c727cfcfe1 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/add_environments.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/add_environments.tsx @@ -35,7 +35,7 @@ interface Props { } type ApiResponse = - APIReturnType<'GET /api/apm/settings/anomaly-detection/environments'>; + APIReturnType<'GET /internal/apm/settings/anomaly-detection/environments'>; const INITIAL_DATA: ApiResponse = { environments: [] }; export function AddEnvironments({ @@ -50,7 +50,7 @@ export function AddEnvironments({ const { data = INITIAL_DATA, status } = useFetcher( (callApmApi) => callApmApi({ - endpoint: `GET /api/apm/settings/anomaly-detection/environments`, + endpoint: `GET /internal/apm/settings/anomaly-detection/environments`, }), [], { preservePreviousData: false } diff --git a/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/create_jobs.ts b/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/create_jobs.ts index a5ab0a3002bb69..3e3493d60f839d 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/create_jobs.ts +++ b/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/create_jobs.ts @@ -28,7 +28,7 @@ export async function createJobs({ }) { try { await callApmApi({ - endpoint: 'POST /api/apm/settings/anomaly-detection/jobs', + endpoint: 'POST /internal/apm/settings/anomaly-detection/jobs', signal: null, params: { body: { environments }, diff --git a/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/index.tsx index 0fe7f9360de0cd..8e1064a71647f6 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/index.tsx @@ -17,7 +17,7 @@ import { useLicenseContext } from '../../../../context/license/use_license_conte import { APIReturnType } from '../../../../services/rest/createCallApmApi'; export type AnomalyDetectionApiResponse = - APIReturnType<'GET /api/apm/settings/anomaly-detection/jobs'>; + APIReturnType<'GET /internal/apm/settings/anomaly-detection/jobs'>; const DEFAULT_VALUE: AnomalyDetectionApiResponse = { jobs: [], @@ -40,7 +40,7 @@ export function AnomalyDetection() { (callApmApi) => { if (canGetJobs) { return callApmApi({ - endpoint: `GET /api/apm/settings/anomaly-detection/jobs`, + endpoint: `GET /internal/apm/settings/anomaly-detection/jobs`, }); } }, diff --git a/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/create_edit_custom_link_flyout/DeleteButton.tsx b/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/create_edit_custom_link_flyout/DeleteButton.tsx index c6547aaff06710..f425979df71e6a 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/create_edit_custom_link_flyout/DeleteButton.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/create_edit_custom_link_flyout/DeleteButton.tsx @@ -49,7 +49,7 @@ async function deleteConfig( ) { try { await callApmApi({ - endpoint: 'DELETE /api/apm/settings/custom_links/{id}', + endpoint: 'DELETE /internal/apm/settings/custom_links/{id}', signal: null, params: { path: { id: customLinkId }, diff --git a/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/create_edit_custom_link_flyout/link_preview.tsx b/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/create_edit_custom_link_flyout/link_preview.tsx index 726d4ba0d65ee1..7ffeafedab4b32 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/create_edit_custom_link_flyout/link_preview.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/create_edit_custom_link_flyout/link_preview.tsx @@ -34,7 +34,7 @@ const fetchTransaction = debounce( async (filters: Filter[], callback: (transaction: Transaction) => void) => { const transaction = await callApmApi({ signal: null, - endpoint: 'GET /api/apm/settings/custom_links/transaction', + endpoint: 'GET /internal/apm/settings/custom_links/transaction', params: { query: convertFiltersToQuery(filters) }, }); callback(transaction); diff --git a/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/create_edit_custom_link_flyout/saveCustomLink.ts b/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/create_edit_custom_link_flyout/saveCustomLink.ts index aa20cf74d1512d..6dcabc4adeda31 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/create_edit_custom_link_flyout/saveCustomLink.ts +++ b/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/create_edit_custom_link_flyout/saveCustomLink.ts @@ -35,7 +35,7 @@ export async function saveCustomLink({ if (id) { await callApmApi({ - endpoint: 'PUT /api/apm/settings/custom_links/{id}', + endpoint: 'PUT /internal/apm/settings/custom_links/{id}', signal: null, params: { path: { id }, @@ -44,7 +44,7 @@ export async function saveCustomLink({ }); } else { await callApmApi({ - endpoint: 'POST /api/apm/settings/custom_links', + endpoint: 'POST /internal/apm/settings/custom_links', signal: null, params: { body: customLink, diff --git a/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/index.tsx index beea1d8276846c..295cc4d008f80d 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/customize_ui/custom_link/index.tsx @@ -38,7 +38,7 @@ export function CustomLinkOverview() { async (callApmApi) => { if (hasValidLicense) { return callApmApi({ - endpoint: 'GET /api/apm/settings/custom_links', + endpoint: 'GET /internal/apm/settings/custom_links', }); } }, diff --git a/x-pack/plugins/apm/public/components/app/Settings/schema/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/schema/index.tsx index 6b7538e61c1307..ac32e22fa3ded2 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/schema/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/schema/index.tsx @@ -20,7 +20,7 @@ import { import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; type FleetMigrationCheckResponse = - APIReturnType<'GET /api/apm/fleet/migration_check'>; + APIReturnType<'GET /internal/apm/fleet/migration_check'>; const APM_DATA_STREAMS_MIGRATION_STATUS_LS = { value: '', @@ -46,7 +46,8 @@ export function Schema() { data = {} as FleetMigrationCheckResponse, status, } = useFetcher( - (callApi) => callApi({ endpoint: 'GET /api/apm/fleet/migration_check' }), + (callApi) => + callApi({ endpoint: 'GET /internal/apm/fleet/migration_check' }), [], { preservePreviousData: false } ); @@ -118,7 +119,7 @@ async function getUnsupportedApmServerConfigs( ) { try { const { unsupported } = await callApmApi({ - endpoint: 'GET /api/apm/fleet/apm_server_schema/unsupported', + endpoint: 'GET /internal/apm/fleet/apm_server_schema/unsupported', signal: null, }); return unsupported; @@ -142,7 +143,7 @@ async function createCloudApmPackagePolicy( updateLocalStorage(FETCH_STATUS.LOADING); try { const { cloudApmPackagePolicy } = await callApmApi({ - endpoint: 'POST /api/apm/fleet/cloud_apm_package_policy', + endpoint: 'POST /internal/apm/fleet/cloud_apm_package_policy', signal: null, }); updateLocalStorage(FETCH_STATUS.SUCCESS); diff --git a/x-pack/plugins/apm/public/components/app/TraceLink/index.tsx b/x-pack/plugins/apm/public/components/app/TraceLink/index.tsx index 2733ee0ddbdba5..1da022f3d933dd 100644 --- a/x-pack/plugins/apm/public/components/app/TraceLink/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TraceLink/index.tsx @@ -29,7 +29,7 @@ export function TraceLink() { (callApmApi) => { if (traceId) { return callApmApi({ - endpoint: 'GET /api/apm/traces/{traceId}/root_transaction', + endpoint: 'GET /internal/apm/traces/{traceId}/root_transaction', params: { path: { traceId, diff --git a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_detail_dependencies_table.tsx b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_detail_dependencies_table.tsx index f98358e3a9c27a..be493f8a98b1ca 100644 --- a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_detail_dependencies_table.tsx +++ b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_detail_dependencies_table.tsx @@ -44,7 +44,7 @@ export function BackendDetailDependenciesTable() { } return callApmApi({ - endpoint: 'GET /api/apm/backends/{backendName}/upstream_services', + endpoint: 'GET /internal/apm/backends/{backendName}/upstream_services', params: { path: { backendName, diff --git a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_error_rate_chart.tsx b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_error_rate_chart.tsx index d48178a8522bef..cf14145dba82a7 100644 --- a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_error_rate_chart.tsx +++ b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_error_rate_chart.tsx @@ -44,7 +44,7 @@ export function BackendFailedTransactionRateChart({ } return callApmApi({ - endpoint: 'GET /api/apm/backends/{backendName}/charts/error_rate', + endpoint: 'GET /internal/apm/backends/{backendName}/charts/error_rate', params: { path: { backendName, diff --git a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_latency_chart.tsx b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_latency_chart.tsx index 759d1539888751..3f5a56d55d8234 100644 --- a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_latency_chart.tsx +++ b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_latency_chart.tsx @@ -40,7 +40,7 @@ export function BackendLatencyChart({ height }: { height: number }) { } return callApmApi({ - endpoint: 'GET /api/apm/backends/{backendName}/charts/latency', + endpoint: 'GET /internal/apm/backends/{backendName}/charts/latency', params: { path: { backendName, diff --git a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_throughput_chart.tsx b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_throughput_chart.tsx index 2cfc7ea317628a..f5d9cb7a7a55e6 100644 --- a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_throughput_chart.tsx +++ b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_throughput_chart.tsx @@ -36,7 +36,7 @@ export function BackendThroughputChart({ height }: { height: number }) { } return callApmApi({ - endpoint: 'GET /api/apm/backends/{backendName}/charts/throughput', + endpoint: 'GET /internal/apm/backends/{backendName}/charts/throughput', params: { path: { backendName, diff --git a/x-pack/plugins/apm/public/components/app/backend_inventory/backend_inventory_dependencies_table/index.tsx b/x-pack/plugins/apm/public/components/app/backend_inventory/backend_inventory_dependencies_table/index.tsx index ea135104982e5f..05eb9892fc108b 100644 --- a/x-pack/plugins/apm/public/components/app/backend_inventory/backend_inventory_dependencies_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/backend_inventory/backend_inventory_dependencies_table/index.tsx @@ -45,7 +45,7 @@ export function BackendInventoryDependenciesTable() { } return callApmApi({ - endpoint: 'GET /api/apm/backends/top_backends', + endpoint: 'GET /internal/apm/backends/top_backends', params: { query: { start, end, environment, numBuckets: 20, offset, kuery }, }, diff --git a/x-pack/plugins/apm/public/components/app/error_group_details/Distribution/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_details/Distribution/index.tsx index b6fc0d4fcf65db..3d1d0ee564ba48 100644 --- a/x-pack/plugins/apm/public/components/app/error_group_details/Distribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/error_group_details/Distribution/index.tsx @@ -35,7 +35,7 @@ const ALERT_RULE_TYPE_ID: typeof ALERT_RULE_TYPE_ID_TYPED = ALERT_RULE_TYPE_ID_NON_TYPED; type ErrorDistributionAPIResponse = - APIReturnType<'GET /api/apm/services/{serviceName}/errors/distribution'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/errors/distribution'>; interface FormattedBucket { x0: number; diff --git a/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/index.tsx index 6e6f323a5525a5..d4ffd8ece9d4d2 100644 --- a/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/index.tsx +++ b/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/index.tsx @@ -54,7 +54,7 @@ const TransactionLinkName = euiStyled.div` `; interface Props { - errorGroup: APIReturnType<'GET /api/apm/services/{serviceName}/errors/{groupId}'>; + errorGroup: APIReturnType<'GET /internal/apm/services/{serviceName}/errors/{groupId}'>; urlParams: ApmUrlParams; kuery: string; } diff --git a/x-pack/plugins/apm/public/components/app/error_group_details/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_details/index.tsx index 9145e019c37eab..01143488929844 100644 --- a/x-pack/plugins/apm/public/components/app/error_group_details/index.tsx +++ b/x-pack/plugins/apm/public/components/app/error_group_details/index.tsx @@ -127,7 +127,7 @@ export function ErrorGroupDetails() { (callApmApi) => { if (start && end) { return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/errors/{groupId}', + endpoint: 'GET /internal/apm/services/{serviceName}/errors/{groupId}', params: { path: { serviceName, diff --git a/x-pack/plugins/apm/public/components/app/error_group_overview/List/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_overview/List/index.tsx index d42c77c06b0abb..d7c5b1f4bc3580 100644 --- a/x-pack/plugins/apm/public/components/app/error_group_overview/List/index.tsx +++ b/x-pack/plugins/apm/public/components/app/error_group_overview/List/index.tsx @@ -48,7 +48,7 @@ const Culprit = euiStyled.div` `; type ErrorGroupItem = - APIReturnType<'GET /api/apm/services/{serviceName}/errors'>['errorGroups'][0]; + APIReturnType<'GET /internal/apm/services/{serviceName}/errors'>['errorGroups'][0]; interface Props { items: ErrorGroupItem[]; diff --git a/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx index 97a3c38b65986c..a445b0d8522c5a 100644 --- a/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx @@ -44,7 +44,7 @@ export function ErrorGroupOverview() { if (start && end) { return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/errors', + endpoint: 'GET /internal/apm/services/{serviceName}/errors', params: { path: { serviceName, diff --git a/x-pack/plugins/apm/public/components/app/service_dependencies/service_dependencies_breakdown_chart.tsx b/x-pack/plugins/apm/public/components/app/service_dependencies/service_dependencies_breakdown_chart.tsx index 426328a8ce9f0b..979a2404dfdf06 100644 --- a/x-pack/plugins/apm/public/components/app/service_dependencies/service_dependencies_breakdown_chart.tsx +++ b/x-pack/plugins/apm/public/components/app/service_dependencies/service_dependencies_breakdown_chart.tsx @@ -29,7 +29,8 @@ export function ServiceDependenciesBreakdownChart({ const { data, status } = useFetcher( (callApmApi) => { return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/dependencies/breakdown', + endpoint: + 'GET /internal/apm/services/{serviceName}/dependencies/breakdown', params: { path: { serviceName, 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 7cd9c7c8e199eb..aea7c1faab6011 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 @@ -64,7 +64,7 @@ function useServicesFetcher() { (callApmApi) => { if (start && end) { return callApmApi({ - endpoint: 'GET /api/apm/services', + endpoint: 'GET /internal/apm/services', params: { query: { environment, @@ -90,7 +90,7 @@ function useServicesFetcher() { (callApmApi) => { if (start && end && mainStatisticsData.items.length) { return callApmApi({ - endpoint: 'GET /api/apm/services/detailed_statistics', + endpoint: 'GET /internal/apm/services/detailed_statistics', params: { query: { environment, diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/__fixtures__/service_api_mock_data.ts b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/__fixtures__/service_api_mock_data.ts index 0f5edb5a4c9cee..85e7eeadc74871 100644 --- a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/__fixtures__/service_api_mock_data.ts +++ b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/__fixtures__/service_api_mock_data.ts @@ -7,7 +7,7 @@ import { APIReturnType } from '../../../../../services/rest/createCallApmApi'; -type ServiceListAPIResponse = APIReturnType<'GET /api/apm/services'>; +type ServiceListAPIResponse = APIReturnType<'GET /internal/apm/services'>; export const items: ServiceListAPIResponse['items'] = [ { diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx index 9c1893b76f7db1..ea65c837a41771 100644 --- a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx @@ -43,10 +43,10 @@ import { ServiceLink } from '../../../shared/service_link'; import { TruncateWithTooltip } from '../../../shared/truncate_with_tooltip'; import { HealthBadge } from './HealthBadge'; -type ServiceListAPIResponse = APIReturnType<'GET /api/apm/services'>; +type ServiceListAPIResponse = APIReturnType<'GET /internal/apm/services'>; type Items = ServiceListAPIResponse['items']; type ServicesDetailedStatisticsAPIResponse = - APIReturnType<'GET /api/apm/services/detailed_statistics'>; + APIReturnType<'GET /internal/apm/services/detailed_statistics'>; type ServiceListItem = ValuesType; diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.test.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.test.tsx index 75aad2283de0bb..69ec1e6b1eb931 100644 --- a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.test.tsx +++ b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.test.tsx @@ -33,7 +33,7 @@ describe('ServiceList', () => { const callApmApiSpy = getCallApmApiSpy().mockImplementation( ({ endpoint }) => { - if (endpoint === 'GET /api/apm/fallback_to_transactions') { + if (endpoint === 'GET /internal/apm/fallback_to_transactions') { return Promise.resolve({ fallbackToTransactions: false }); } return Promise.reject(`Response for ${endpoint} is not defined`); diff --git a/x-pack/plugins/apm/public/components/app/service_logs/index.tsx b/x-pack/plugins/apm/public/components/app/service_logs/index.tsx index 79818473d26b1c..bb32919196f842 100644 --- a/x-pack/plugins/apm/public/components/app/service_logs/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_logs/index.tsx @@ -35,7 +35,7 @@ export function ServiceLogs() { (callApmApi) => { if (start && end) { return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/infrastructure', + endpoint: 'GET /internal/apm/services/{serviceName}/infrastructure', params: { path: { serviceName }, query: { @@ -92,7 +92,7 @@ export function ServiceLogs() { } export const getInfrastructureKQLFilter = ( - data?: APIReturnType<'GET /api/apm/services/{serviceName}/infrastructure'> + data?: APIReturnType<'GET /internal/apm/services/{serviceName}/infrastructure'> ) => { const containerIds = data?.serviceInfrastructure?.containerIds ?? []; const hostNames = data?.serviceInfrastructure?.hostNames ?? []; diff --git a/x-pack/plugins/apm/public/components/app/service_map/Popover/backend_contents.tsx b/x-pack/plugins/apm/public/components/app/service_map/Popover/backend_contents.tsx index c01cf4579fdbdb..c04619338f80be 100644 --- a/x-pack/plugins/apm/public/components/app/service_map/Popover/backend_contents.tsx +++ b/x-pack/plugins/apm/public/components/app/service_map/Popover/backend_contents.tsx @@ -38,7 +38,7 @@ export function BackendContents({ (callApmApi) => { if (backendName) { return callApmApi({ - endpoint: 'GET /api/apm/service-map/backend/{backendName}', + endpoint: 'GET /internal/apm/service-map/backend/{backendName}', params: { path: { backendName }, query: { diff --git a/x-pack/plugins/apm/public/components/app/service_map/Popover/service_contents.tsx b/x-pack/plugins/apm/public/components/app/service_map/Popover/service_contents.tsx index 5eef580793d106..f320123ce07235 100644 --- a/x-pack/plugins/apm/public/components/app/service_map/Popover/service_contents.tsx +++ b/x-pack/plugins/apm/public/components/app/service_map/Popover/service_contents.tsx @@ -47,7 +47,7 @@ export function ServiceContents({ (callApmApi) => { if (serviceName && start && end) { return callApmApi({ - endpoint: 'GET /api/apm/service-map/service/{serviceName}', + endpoint: 'GET /internal/apm/service-map/service/{serviceName}', params: { path: { serviceName }, query: { environment, start, end }, 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 7499eb9cd658cf..75d5837f738c5c 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 @@ -124,7 +124,7 @@ export function ServiceMap({ return callApmApi({ isCachable: false, - endpoint: 'GET /api/apm/service-map', + endpoint: 'GET /internal/apm/service-map', params: { query: { start, diff --git a/x-pack/plugins/apm/public/components/app/service_node_metrics/index.tsx b/x-pack/plugins/apm/public/components/app/service_node_metrics/index.tsx index 1f83ad317e9622..19527cd0849898 100644 --- a/x-pack/plugins/apm/public/components/app/service_node_metrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_node_metrics/index.tsx @@ -85,7 +85,7 @@ export function ServiceNodeMetrics() { if (start && end) { return callApmApi({ endpoint: - 'GET /api/apm/services/{serviceName}/node/{serviceNodeName}/metadata', + 'GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata', params: { path: { serviceName, serviceNodeName }, query: { diff --git a/x-pack/plugins/apm/public/components/app/service_node_overview/index.tsx b/x-pack/plugins/apm/public/components/app/service_node_overview/index.tsx index bef87891d7416f..04bb578b0c4348 100644 --- a/x-pack/plugins/apm/public/components/app/service_node_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_node_overview/index.tsx @@ -48,7 +48,7 @@ function ServiceNodeOverview() { return undefined; } return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/serviceNodes', + endpoint: 'GET /internal/apm/services/{serviceName}/serviceNodes', params: { path: { serviceName, diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview.test.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview.test.tsx index 62cefa5de47fa8..42a0c68535efed 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview.test.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview.test.tsx @@ -99,21 +99,21 @@ describe('ServiceOverview', () => { /* eslint-disable @typescript-eslint/naming-convention */ const calls = { - 'GET /api/apm/services/{serviceName}/error_groups/main_statistics': { + 'GET /internal/apm/services/{serviceName}/error_groups/main_statistics': { error_groups: [] as any[], }, - 'GET /api/apm/services/{serviceName}/transactions/groups/main_statistics': + 'GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics': { transactionGroups: [] as any[], totalTransactionGroups: 0, isAggregationAccurate: true, }, - 'GET /api/apm/services/{serviceName}/dependencies': { + 'GET /internal/apm/services/{serviceName}/dependencies': { serviceDependencies: [], }, - 'GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics': + 'GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics': [], - 'GET /api/apm/services/{serviceName}/transactions/charts/latency': { + 'GET /internal/apm/services/{serviceName}/transactions/charts/latency': { currentPeriod: { overallAvgDuration: null, latencyTimeseries: [], @@ -123,26 +123,27 @@ describe('ServiceOverview', () => { latencyTimeseries: [], }, }, - 'GET /api/apm/services/{serviceName}/throughput': { + 'GET /internal/apm/services/{serviceName}/throughput': { currentPeriod: [], previousPeriod: [], }, - 'GET /api/apm/services/{serviceName}/transactions/charts/error_rate': { - currentPeriod: { - transactionErrorRate: [], - noHits: true, - average: null, - }, - previousPeriod: { - transactionErrorRate: [], - noHits: true, - average: null, + 'GET /internal/apm/services/{serviceName}/transactions/charts/error_rate': + { + currentPeriod: { + transactionErrorRate: [], + noHits: true, + average: null, + }, + previousPeriod: { + transactionErrorRate: [], + noHits: true, + average: null, + }, }, - }, 'GET /api/apm/services/{serviceName}/annotation/search': { annotations: [], }, - 'GET /api/apm/fallback_to_transactions': { + 'GET /internal/apm/fallback_to_transactions': { fallbackToTransactions: false, }, }; 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 b035d626c371aa..b29daa1dd55851 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 @@ -59,7 +59,7 @@ export function ServiceOverviewDependenciesTable({ } return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/dependencies', + endpoint: 'GET /internal/apm/services/{serviceName}/dependencies', params: { path: { serviceName }, query: { start, end, environment, numBuckets: 20, offset }, diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/get_columns.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/get_columns.tsx index 86f1907365bf6c..14a8b59cd7826a 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/get_columns.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/get_columns.tsx @@ -16,9 +16,9 @@ import { TimestampTooltip } from '../../../shared/TimestampTooltip'; import { TruncateWithTooltip } from '../../../shared/truncate_with_tooltip'; type ErrorGroupMainStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/error_groups/main_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/error_groups/main_statistics'>; type ErrorGroupDetailedStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/error_groups/detailed_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/error_groups/detailed_statistics'>; export function getColumns({ serviceName, diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/index.tsx index ebf634fd6b186a..d7116763780398 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/index.tsx @@ -30,9 +30,9 @@ interface Props { serviceName: string; } type ErrorGroupMainStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/error_groups/main_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/error_groups/main_statistics'>; type ErrorGroupDetailedStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/error_groups/detailed_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/error_groups/detailed_statistics'>; type SortDirection = 'asc' | 'desc'; type SortField = 'name' | 'lastSeen' | 'occurrences'; @@ -97,7 +97,7 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) { } return callApmApi({ endpoint: - 'GET /api/apm/services/{serviceName}/error_groups/main_statistics', + 'GET /internal/apm/services/{serviceName}/error_groups/main_statistics', params: { path: { serviceName }, query: { @@ -150,7 +150,7 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) { if (requestId && items.length && start && end && transactionType) { return callApmApi({ endpoint: - 'GET /api/apm/services/{serviceName}/error_groups/detailed_statistics', + 'GET /internal/apm/services/{serviceName}/error_groups/detailed_statistics', params: { path: { serviceName }, query: { diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_chart_and_table.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_chart_and_table.tsx index ab42d9b80634ad..74a9a60afd9157 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_chart_and_table.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_chart_and_table.tsx @@ -28,9 +28,9 @@ interface ServiceOverviewInstancesChartAndTableProps { } type ApiResponseMainStats = - APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics'>; type ApiResponseDetailedStats = - APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/detailed_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics'>; const INITIAL_STATE_MAIN_STATS = { currentPeriodItems: [] as ApiResponseMainStats['currentPeriod'], @@ -100,7 +100,7 @@ export function ServiceOverviewInstancesChartAndTable({ return callApmApi({ endpoint: - 'GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics', + 'GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics', params: { path: { serviceName, @@ -181,7 +181,7 @@ export function ServiceOverviewInstancesChartAndTable({ return callApmApi({ endpoint: - 'GET /api/apm/services/{serviceName}/service_overview_instances/detailed_statistics', + 'GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics', params: { path: { serviceName, diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/get_columns.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/get_columns.tsx index 3a80e0b0753231..853ea37112ad8f 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/get_columns.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/get_columns.tsx @@ -33,11 +33,11 @@ import { TruncateWithTooltip } from '../../../shared/truncate_with_tooltip'; import { InstanceActionsMenu } from './instance_actions_menu'; type ServiceInstanceMainStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics'>; type MainStatsServiceInstanceItem = ServiceInstanceMainStatistics['currentPeriod'][0]; type ServiceInstanceDetailedStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/detailed_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics'>; export function getColumns({ serviceName, diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx index a8a93e8d4473e2..9084ffdda59f85 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx @@ -29,11 +29,11 @@ import { useApmParams } from '../../../../hooks/use_apm_params'; import { useBreakpoints } from '../../../../hooks/use_breakpoints'; type ServiceInstanceMainStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics'>; type MainStatsServiceInstanceItem = ServiceInstanceMainStatistics['currentPeriod'][0]; type ServiceInstanceDetailedStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/detailed_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics'>; export interface TableOptions { pageIndex: number; diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts index cd7e64ae39668d..7e7f30065c9585 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts @@ -17,7 +17,7 @@ import { } from '../../../../shared/transaction_action_menu/sections_helper'; type InstaceDetails = - APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}'>; function getInfraMetricsQuery(timestamp?: string) { if (!timestamp) { diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_details.test.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_details.test.tsx index 3a0ed21ca9808d..b8e18eec43e6a0 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_details.test.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_details.test.tsx @@ -16,7 +16,7 @@ import { InstanceDetails } from './intance_details'; import * as useInstanceDetailsFetcher from './use_instance_details_fetcher'; type ServiceInstanceDetails = - APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}'>; describe('InstanceDetails', () => { it('renders loading spinner when data is being fetched', () => { diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/intance_details.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/intance_details.tsx index 7a194039e0d4ca..fad5628b2192dc 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/intance_details.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/intance_details.tsx @@ -34,7 +34,7 @@ import { getCloudIcon, getContainerIcon } from '../../../shared/service_icons'; import { useInstanceDetailsFetcher } from './use_instance_details_fetcher'; type ServiceInstanceDetails = - APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}'>; interface Props { serviceName: string; diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/use_instance_details_fetcher.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/use_instance_details_fetcher.tsx index c1018d6d742fa7..de833b9b3be119 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/use_instance_details_fetcher.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/use_instance_details_fetcher.tsx @@ -28,7 +28,7 @@ export function useInstanceDetailsFetcher({ } return callApmApi({ endpoint: - 'GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}', + 'GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}', params: { path: { serviceName, diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_throughput_chart.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_throughput_chart.tsx index c3d17b9f18a985..0780c2d2727152 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_throughput_chart.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_throughput_chart.tsx @@ -69,7 +69,7 @@ export function ServiceOverviewThroughputChart({ (callApmApi) => { if (serviceName && transactionType && start && end) { return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/throughput', + endpoint: 'GET /internal/apm/services/{serviceName}/throughput', params: { path: { serviceName, diff --git a/x-pack/plugins/apm/public/components/app/service_profiling/index.tsx b/x-pack/plugins/apm/public/components/app/service_profiling/index.tsx index 15caa833764b91..5342ae8e0db284 100644 --- a/x-pack/plugins/apm/public/components/app/service_profiling/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_profiling/index.tsx @@ -19,7 +19,7 @@ import { ServiceProfilingFlamegraph } from './service_profiling_flamegraph'; import { ServiceProfilingTimeline } from './service_profiling_timeline'; type ApiResponse = - APIReturnType<'GET /api/apm/services/{serviceName}/profiling/timeline'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/profiling/timeline'>; const DEFAULT_DATA: ApiResponse = { profilingTimeline: [] }; export function ServiceProfiling() { @@ -38,7 +38,7 @@ export function ServiceProfiling() { } return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/profiling/timeline', + endpoint: 'GET /internal/apm/services/{serviceName}/profiling/timeline', params: { path: { serviceName }, query: { diff --git a/x-pack/plugins/apm/public/components/app/service_profiling/service_profiling_flamegraph.tsx b/x-pack/plugins/apm/public/components/app/service_profiling/service_profiling_flamegraph.tsx index a2ce4dcf7e83f2..8626c4a3b061c2 100644 --- a/x-pack/plugins/apm/public/components/app/service_profiling/service_profiling_flamegraph.tsx +++ b/x-pack/plugins/apm/public/components/app/service_profiling/service_profiling_flamegraph.tsx @@ -147,7 +147,8 @@ export function ServiceProfilingFlamegraph({ } return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/profiling/statistics', + endpoint: + 'GET /internal/apm/services/{serviceName}/profiling/statistics', params: { path: { serviceName, diff --git a/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx b/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx index 63cd27cba41e8b..9725df9809ea0d 100644 --- a/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx @@ -16,7 +16,7 @@ import { useFallbackToTransactionsFetcher } from '../../../hooks/use_fallback_to import { AggregatedTransactionsBadge } from '../../shared/aggregated_transactions_badge'; import { useTimeRange } from '../../../hooks/use_time_range'; -type TracesAPIResponse = APIReturnType<'GET /api/apm/traces'>; +type TracesAPIResponse = APIReturnType<'GET /internal/apm/traces'>; const DEFAULT_RESPONSE: TracesAPIResponse = { items: [], }; @@ -35,7 +35,7 @@ export function TraceOverview() { (callApmApi) => { if (start && end) { return callApmApi({ - endpoint: 'GET /api/apm/traces', + endpoint: 'GET /internal/apm/traces', params: { query: { environment, diff --git a/x-pack/plugins/apm/public/components/app/trace_overview/trace_list.tsx b/x-pack/plugins/apm/public/components/app/trace_overview/trace_list.tsx index 7c4e0ffca1f582..0fc25b28b60e8c 100644 --- a/x-pack/plugins/apm/public/components/app/trace_overview/trace_list.tsx +++ b/x-pack/plugins/apm/public/components/app/trace_overview/trace_list.tsx @@ -20,7 +20,7 @@ import { ImpactBar } from '../../shared/ImpactBar'; import { TransactionDetailLink } from '../../shared/Links/apm/transaction_detail_link'; import { ITableColumn, ManagedTable } from '../../shared/managed_table'; -type TraceGroup = APIReturnType<'GET /api/apm/traces'>['items'][0]; +type TraceGroup = APIReturnType<'GET /internal/apm/traces'>['items'][0]; const StyledTransactionLink = euiStyled(TransactionDetailLink)` font-size: ${({ theme }) => theme.eui.euiFontSizeS}; diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/use_waterfall_fetcher.ts b/x-pack/plugins/apm/public/components/app/transaction_details/use_waterfall_fetcher.ts index 12bb8dbe12e4b3..e7fbc315522e46 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/use_waterfall_fetcher.ts +++ b/x-pack/plugins/apm/public/components/app/transaction_details/use_waterfall_fetcher.ts @@ -36,7 +36,7 @@ export function useWaterfallFetcher() { (callApmApi) => { if (traceId && start && end) { return callApmApi({ - endpoint: 'GET /api/apm/traces/{traceId}', + endpoint: 'GET /internal/apm/traces/{traceId}', params: { path: { traceId }, query: { diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/waterfall_helpers.ts b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/waterfall_helpers.ts index 9501ad1839d46a..661ba2556d84ea 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/waterfall_helpers.ts +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/Waterfall/waterfall_helpers/waterfall_helpers.ts @@ -12,7 +12,7 @@ import { APMError } from '../../../../../../../../typings/es_schemas/ui/apm_erro import { Span } from '../../../../../../../../typings/es_schemas/ui/span'; import { Transaction } from '../../../../../../../../typings/es_schemas/ui/transaction'; -type TraceAPIResponse = APIReturnType<'GET /api/apm/traces/{traceId}'>; +type TraceAPIResponse = APIReturnType<'GET /internal/apm/traces/{traceId}'>; interface IWaterfallGroup { [key: string]: IWaterfallSpanOrTransaction[]; diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfallContainer.stories.data.ts b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfallContainer.stories.data.ts index 87150cdfc83a8f..60285c835bbf3d 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfallContainer.stories.data.ts +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfallContainer.stories.data.ts @@ -16,7 +16,7 @@ export const location = { hash: '', } as Location; -type TraceAPIResponse = APIReturnType<'GET /api/apm/traces/{traceId}'>; +type TraceAPIResponse = APIReturnType<'GET /internal/apm/traces/{traceId}'>; export const urlParams = { start: '2020-03-22T15:16:38.742Z', diff --git a/x-pack/plugins/apm/public/components/app/transaction_link/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_link/index.tsx index 468a90f6b17de6..251daf3d0d0326 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_link/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_link/index.tsx @@ -28,7 +28,7 @@ export function TransactionLink() { (callApmApi) => { if (transactionId) { return callApmApi({ - endpoint: 'GET /api/apm/transactions/{transactionId}', + endpoint: 'GET /internal/apm/transactions/{transactionId}', params: { path: { transactionId, diff --git a/x-pack/plugins/apm/public/components/routing/templates/apm_main_template.tsx b/x-pack/plugins/apm/public/components/routing/templates/apm_main_template.tsx index ac0b8a1517b20d..14bf7de789c98f 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/apm_main_template.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/apm_main_template.tsx @@ -49,7 +49,7 @@ export function ApmMainTemplate({ services.observability.navigation.PageTemplate; const { data } = useFetcher((callApmApi) => { - return callApmApi({ endpoint: 'GET /api/apm/has_data' }); + return callApmApi({ endpoint: 'GET /internal/apm/has_data' }); }, []); const noDataConfig = getNoDataConfig({ diff --git a/x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/index.tsx b/x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/index.tsx index f6ffc34ecee029..a0cf2a1aec4857 100644 --- a/x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/index.tsx @@ -20,7 +20,7 @@ export function ErrorMetadata({ error }: Props) { const { data: errorEvent, status } = useFetcher( (callApmApi) => { return callApmApi({ - endpoint: 'GET /api/apm/event_metadata/{processorEvent}/{id}', + endpoint: 'GET /internal/apm/event_metadata/{processorEvent}/{id}', params: { path: { processorEvent: ProcessorEvent.error, diff --git a/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/index.tsx b/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/index.tsx index bf5702b4acf3ec..166440d0975b05 100644 --- a/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/index.tsx @@ -20,7 +20,7 @@ export function SpanMetadata({ span }: Props) { const { data: spanEvent, status } = useFetcher( (callApmApi) => { return callApmApi({ - endpoint: 'GET /api/apm/event_metadata/{processorEvent}/{id}', + endpoint: 'GET /internal/apm/event_metadata/{processorEvent}/{id}', params: { path: { processorEvent: ProcessorEvent.span, diff --git a/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/index.tsx b/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/index.tsx index 32c0101c73b4d6..b437173c4b6326 100644 --- a/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/index.tsx @@ -20,7 +20,7 @@ export function TransactionMetadata({ transaction }: Props) { const { data: transactionEvent, status } = useFetcher( (callApmApi) => { return callApmApi({ - endpoint: 'GET /api/apm/event_metadata/{processorEvent}/{id}', + endpoint: 'GET /internal/apm/event_metadata/{processorEvent}/{id}', params: { path: { processorEvent: ProcessorEvent.transaction, 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/shared/apm_header_action_menu/anomaly_detection_setup_link.tsx index c84cbc9a4b1041..970cc886d30bdb 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/shared/apm_header_action_menu/anomaly_detection_setup_link.tsx @@ -27,7 +27,7 @@ import { APIReturnType } from '../../../services/rest/createCallApmApi'; import { getAPMHref } from '../Links/apm/APMLink'; export type AnomalyDetectionApiResponse = - APIReturnType<'GET /api/apm/settings/anomaly-detection/jobs'>; + APIReturnType<'GET /internal/apm/settings/anomaly-detection/jobs'>; const DEFAULT_DATA = { jobs: [], hasLegacyJobs: false }; diff --git a/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.test.tsx b/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.test.tsx index e63f7fbc79ab2c..4573e8e5a174f3 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.test.tsx @@ -30,7 +30,7 @@ import { APIReturnType } from '../../../../services/rest/createCallApmApi'; import { getAlertAnnotations } from './get_alert_annotations'; type Alert = ValuesType< - APIReturnType<'GET /api/apm/services/{serviceName}/alerts'>['alerts'] + APIReturnType<'GET /internal/apm/services/{serviceName}/alerts'>['alerts'] >; const euiColorDanger = 'red'; diff --git a/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.tsx b/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.tsx index 39e1ce59de4bca..f4c47a9247e753 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.tsx @@ -46,7 +46,7 @@ const ALERT_RULE_TYPE_ID: typeof ALERT_RULE_TYPE_ID_TYPED = const ALERT_RULE_NAME: typeof ALERT_RULE_NAME_TYPED = ALERT_RULE_NAME_NON_TYPED; type Alert = ValuesType< - APIReturnType<'GET /api/apm/services/{serviceName}/alerts'>['alerts'] + APIReturnType<'GET /internal/apm/services/{serviceName}/alerts'>['alerts'] >; function getAlertColor({ diff --git a/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/custom_tooltip.stories.tsx b/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/custom_tooltip.stories.tsx index d39770b68d5b63..56138a676a29de 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/custom_tooltip.stories.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/custom_tooltip.stories.tsx @@ -12,7 +12,7 @@ import { getDurationFormatter } from '../../../../../common/utils/formatters'; import { CustomTooltip } from './custom_tooltip'; type ServiceInstanceMainStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics'>; type MainStatsServiceInstanceItem = ServiceInstanceMainStatistics['currentPeriod'][0]; diff --git a/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/custom_tooltip.tsx b/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/custom_tooltip.tsx index 7289ffddd0eab9..2974f909615f4d 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/custom_tooltip.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/custom_tooltip.tsx @@ -18,7 +18,7 @@ import { import { useTheme } from '../../../../hooks/use_theme'; type ServiceInstanceMainStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics'>; type MainStatsServiceInstanceItem = ServiceInstanceMainStatistics['currentPeriod'][0]; diff --git a/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/index.tsx index 5c974664eb1d3a..30bf5908ef3767 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/index.tsx @@ -37,7 +37,7 @@ import { getResponseTimeTickFormatter } from '../transaction_charts/helper'; import { CustomTooltip } from './custom_tooltip'; type ApiResponseMainStats = - APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics'>; export interface InstancesLatencyDistributionChartProps { height: number; diff --git a/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.stories.tsx b/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.stories.tsx index 511b605e3c22c8..ad51e66f1959c3 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.stories.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.stories.tsx @@ -42,8 +42,8 @@ import { import { LatencyChart } from './'; interface Args { - alertsResponse: APIReturnType<'GET /api/apm/services/{serviceName}/alerts'>; - latencyChartResponse: APIReturnType<'GET /api/apm/services/{serviceName}/transactions/charts/latency'>; + alertsResponse: APIReturnType<'GET /internal/apm/services/{serviceName}/alerts'>; + latencyChartResponse: APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/charts/latency'>; } export default { @@ -70,7 +70,7 @@ export default { basePath: { prepend: () => {} }, get: (endpoint: string) => { switch (endpoint) { - case `/api/apm/services/${serviceName}/transactions/charts/latency`: + case `/internal/apm/services/${serviceName}/transactions/charts/latency`: return latencyChartResponse; default: return {}; diff --git a/x-pack/plugins/apm/public/components/shared/charts/transaction_breakdown_chart/use_transaction_breakdown.ts b/x-pack/plugins/apm/public/components/shared/charts/transaction_breakdown_chart/use_transaction_breakdown.ts index e814459fbf519a..079b8455de7ad2 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/transaction_breakdown_chart/use_transaction_breakdown.ts +++ b/x-pack/plugins/apm/public/components/shared/charts/transaction_breakdown_chart/use_transaction_breakdown.ts @@ -39,7 +39,7 @@ export function useTransactionBreakdown({ if (serviceName && start && end && transactionType) { return callApmApi({ endpoint: - 'GET /api/apm/services/{serviceName}/transaction/charts/breakdown', + 'GET /internal/apm/services/{serviceName}/transaction/charts/breakdown', params: { path: { serviceName }, query: { diff --git a/x-pack/plugins/apm/public/components/shared/charts/transaction_error_rate_chart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/transaction_error_rate_chart/index.tsx index 88788c7c3d39ff..95b73a5276b8a9 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/transaction_error_rate_chart/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/transaction_error_rate_chart/index.tsx @@ -36,7 +36,7 @@ interface Props { } type ErrorRate = - APIReturnType<'GET /api/apm/services/{serviceName}/transactions/charts/error_rate'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/charts/error_rate'>; const INITIAL_STATE: ErrorRate = { currentPeriod: { @@ -82,7 +82,7 @@ export function TransactionErrorRateChart({ if (transactionType && serviceName && start && end) { return callApmApi({ endpoint: - 'GET /api/apm/services/{serviceName}/transactions/charts/error_rate', + 'GET /internal/apm/services/{serviceName}/transactions/charts/error_rate', params: { path: { serviceName, diff --git a/x-pack/plugins/apm/public/components/shared/service_icons/cloud_details.tsx b/x-pack/plugins/apm/public/components/shared/service_icons/cloud_details.tsx index 2c706fa863a935..eded3ff9fd1c6f 100644 --- a/x-pack/plugins/apm/public/components/shared/service_icons/cloud_details.tsx +++ b/x-pack/plugins/apm/public/components/shared/service_icons/cloud_details.tsx @@ -12,7 +12,7 @@ import React from 'react'; import { APIReturnType } from '../../../services/rest/createCallApmApi'; type ServiceDetailsReturnType = - APIReturnType<'GET /api/apm/services/{serviceName}/metadata/details'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/metadata/details'>; interface Props { cloud: ServiceDetailsReturnType['cloud']; diff --git a/x-pack/plugins/apm/public/components/shared/service_icons/container_details.tsx b/x-pack/plugins/apm/public/components/shared/service_icons/container_details.tsx index 75f7c23a78085f..cd2e3a518b3b33 100644 --- a/x-pack/plugins/apm/public/components/shared/service_icons/container_details.tsx +++ b/x-pack/plugins/apm/public/components/shared/service_icons/container_details.tsx @@ -13,7 +13,7 @@ import { asInteger } from '../../../../common/utils/formatters'; import { APIReturnType } from '../../../services/rest/createCallApmApi'; type ServiceDetailsReturnType = - APIReturnType<'GET /api/apm/services/{serviceName}/metadata/details'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/metadata/details'>; interface Props { container: ServiceDetailsReturnType['container']; diff --git a/x-pack/plugins/apm/public/components/shared/service_icons/index.test.tsx b/x-pack/plugins/apm/public/components/shared/service_icons/index.test.tsx index bd90cae0277afd..b04fe26e1a8bc9 100644 --- a/x-pack/plugins/apm/public/components/shared/service_icons/index.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/service_icons/index.test.tsx @@ -186,7 +186,7 @@ describe('ServiceIcons', () => { }; it('Shows loading spinner while fetching data', () => { const apisMockData = { - 'GET /api/apm/services/{serviceName}/metadata/icons': { + 'GET /internal/apm/services/{serviceName}/metadata/icons': { data: { agentName: 'java', containerType: 'Kubernetes', @@ -195,7 +195,7 @@ describe('ServiceIcons', () => { status: fetcherHook.FETCH_STATUS.SUCCESS, refetch: jest.fn(), }, - 'GET /api/apm/services/{serviceName}/metadata/details': { + 'GET /internal/apm/services/{serviceName}/metadata/details': { data: undefined, status: fetcherHook.FETCH_STATUS.LOADING, refetch: jest.fn(), @@ -228,7 +228,7 @@ describe('ServiceIcons', () => { it('shows service content', () => { const apisMockData = { - 'GET /api/apm/services/{serviceName}/metadata/icons': { + 'GET /internal/apm/services/{serviceName}/metadata/icons': { data: { agentName: 'java', containerType: 'Kubernetes', @@ -237,7 +237,7 @@ describe('ServiceIcons', () => { status: fetcherHook.FETCH_STATUS.SUCCESS, refetch: jest.fn(), }, - 'GET /api/apm/services/{serviceName}/metadata/details': { + 'GET /internal/apm/services/{serviceName}/metadata/details': { data: { service: { versions: ['v1.0.0'] } }, status: fetcherHook.FETCH_STATUS.SUCCESS, refetch: jest.fn(), diff --git a/x-pack/plugins/apm/public/components/shared/service_icons/index.tsx b/x-pack/plugins/apm/public/components/shared/service_icons/index.tsx index 780c3b0222f13e..77639ea1f6d729 100644 --- a/x-pack/plugins/apm/public/components/shared/service_icons/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/service_icons/index.tsx @@ -71,7 +71,7 @@ export function ServiceIcons({ start, end, serviceName }: Props) { (callApmApi) => { if (serviceName && start && end) { return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/metadata/icons', + endpoint: 'GET /internal/apm/services/{serviceName}/metadata/icons', params: { path: { serviceName }, query: { start, end }, @@ -87,7 +87,7 @@ export function ServiceIcons({ start, end, serviceName }: Props) { if (selectedIconPopover && serviceName && start && end) { return callApmApi({ isCachable: true, - endpoint: 'GET /api/apm/services/{serviceName}/metadata/details', + endpoint: 'GET /internal/apm/services/{serviceName}/metadata/details', params: { path: { serviceName }, query: { start, end }, diff --git a/x-pack/plugins/apm/public/components/shared/service_icons/service_details.tsx b/x-pack/plugins/apm/public/components/shared/service_icons/service_details.tsx index daf253f6bc0a97..9ab8b5ba8a1f04 100644 --- a/x-pack/plugins/apm/public/components/shared/service_icons/service_details.tsx +++ b/x-pack/plugins/apm/public/components/shared/service_icons/service_details.tsx @@ -12,7 +12,7 @@ import React from 'react'; import { APIReturnType } from '../../../services/rest/createCallApmApi'; type ServiceDetailsReturnType = - APIReturnType<'GET /api/apm/services/{serviceName}/metadata/details'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/metadata/details'>; interface Props { service: ServiceDetailsReturnType['service']; diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/custom_link_menu_section/index.tsx b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/custom_link_menu_section/index.tsx index bc234b88a08e4f..ea247d1907a261 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/custom_link_menu_section/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/custom_link_menu_section/index.tsx @@ -61,7 +61,7 @@ export function CustomLinkMenuSection({ (callApmApi) => callApmApi({ isCachable: false, - endpoint: 'GET /api/apm/settings/custom_links', + endpoint: 'GET /internal/apm/settings/custom_links', params: { query: convertFiltersToQuery(filters) }, }), [filters] diff --git a/x-pack/plugins/apm/public/components/shared/transactions_table/get_columns.tsx b/x-pack/plugins/apm/public/components/shared/transactions_table/get_columns.tsx index b11a2994f1caaf..18e9beb2c87954 100644 --- a/x-pack/plugins/apm/public/components/shared/transactions_table/get_columns.tsx +++ b/x-pack/plugins/apm/public/components/shared/transactions_table/get_columns.tsx @@ -28,13 +28,13 @@ import { TruncateWithTooltip } from '../truncate_with_tooltip'; import { getLatencyColumnLabel } from './get_latency_column_label'; type TransactionGroupMainStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/transactions/groups/main_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics'>; type ServiceTransactionGroupItem = ValuesType< TransactionGroupMainStatistics['transactionGroups'] >; type TransactionGroupDetailedStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/transactions/groups/detailed_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics'>; export function getColumns({ serviceName, diff --git a/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx b/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx index 6f91684de0ee5b..d6d955b8ef5abe 100644 --- a/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx @@ -30,7 +30,7 @@ import { ElasticDocsLink } from '../Links/ElasticDocsLink'; import { useBreakpoints } from '../../../hooks/use_breakpoints'; type ApiResponse = - APIReturnType<'GET /api/apm/services/{serviceName}/transactions/groups/main_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics'>; interface InitialState { requestId: string; @@ -116,7 +116,7 @@ export function TransactionsTable({ } return callApmApi({ endpoint: - 'GET /api/apm/services/{serviceName}/transactions/groups/main_statistics', + 'GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics', params: { path: { serviceName }, query: { @@ -189,7 +189,7 @@ export function TransactionsTable({ ) { return callApmApi({ endpoint: - 'GET /api/apm/services/{serviceName}/transactions/groups/detailed_statistics', + 'GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics', params: { path: { serviceName }, query: { diff --git a/x-pack/plugins/apm/public/context/anomaly_detection_jobs/anomaly_detection_jobs_context.tsx b/x-pack/plugins/apm/public/context/anomaly_detection_jobs/anomaly_detection_jobs_context.tsx index b8d6feda826a5e..bf9f2941fa2fb0 100644 --- a/x-pack/plugins/apm/public/context/anomaly_detection_jobs/anomaly_detection_jobs_context.tsx +++ b/x-pack/plugins/apm/public/context/anomaly_detection_jobs/anomaly_detection_jobs_context.tsx @@ -10,7 +10,7 @@ import { FETCH_STATUS, useFetcher } from '../../hooks/use_fetcher'; import { APIReturnType } from '../../services/rest/createCallApmApi'; export interface AnomalyDetectionJobsContextValue { - anomalyDetectionJobsData?: APIReturnType<'GET /api/apm/settings/anomaly-detection/jobs'>; + anomalyDetectionJobsData?: APIReturnType<'GET /internal/apm/settings/anomaly-detection/jobs'>; anomalyDetectionJobsStatus: FETCH_STATUS; anomalyDetectionJobsRefetch: () => void; } @@ -30,7 +30,7 @@ export function AnomalyDetectionJobsContextProvider({ const { data, status } = useFetcher( (callApmApi) => callApmApi({ - endpoint: `GET /api/apm/settings/anomaly-detection/jobs`, + endpoint: `GET /internal/apm/settings/anomaly-detection/jobs`, }), [fetchId], // eslint-disable-line react-hooks/exhaustive-deps { showToastOnError: false } diff --git a/x-pack/plugins/apm/public/context/apm_backend/apm_backend_context.tsx b/x-pack/plugins/apm/public/context/apm_backend/apm_backend_context.tsx index d6cc139e72b647..6093f05c2cb024 100644 --- a/x-pack/plugins/apm/public/context/apm_backend/apm_backend_context.tsx +++ b/x-pack/plugins/apm/public/context/apm_backend/apm_backend_context.tsx @@ -15,7 +15,7 @@ export const ApmBackendContext = createContext< | { backendName: string; metadata: { - data?: APIReturnType<'GET /api/apm/backends/{backendName}/metadata'>; + data?: APIReturnType<'GET /internal/apm/backends/{backendName}/metadata'>; status?: FETCH_STATUS; }; } @@ -41,7 +41,7 @@ export function ApmBackendContextProvider({ } return callApmApi({ - endpoint: 'GET /api/apm/backends/{backendName}/metadata', + endpoint: 'GET /internal/apm/backends/{backendName}/metadata', params: { path: { backendName, diff --git a/x-pack/plugins/apm/public/context/apm_service/apm_service_context.tsx b/x-pack/plugins/apm/public/context/apm_service/apm_service_context.tsx index d6b052a5dc8843..9d207eee2fbaa6 100644 --- a/x-pack/plugins/apm/public/context/apm_service/apm_service_context.tsx +++ b/x-pack/plugins/apm/public/context/apm_service/apm_service_context.tsx @@ -20,7 +20,7 @@ import { useApmParams } from '../../hooks/use_apm_params'; import { useTimeRange } from '../../hooks/use_time_range'; export type APMServiceAlert = ValuesType< - APIReturnType<'GET /api/apm/services/{serviceName}/alerts'>['alerts'] + APIReturnType<'GET /internal/apm/services/{serviceName}/alerts'>['alerts'] >; export const APMServiceContext = createContext<{ diff --git a/x-pack/plugins/apm/public/context/apm_service/use_service_agent_fetcher.ts b/x-pack/plugins/apm/public/context/apm_service/use_service_agent_fetcher.ts index e30fd962e5a928..0202ff3a10123c 100644 --- a/x-pack/plugins/apm/public/context/apm_service/use_service_agent_fetcher.ts +++ b/x-pack/plugins/apm/public/context/apm_service/use_service_agent_fetcher.ts @@ -29,7 +29,7 @@ export function useServiceAgentFetcher({ (callApmApi) => { if (serviceName) { return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/agent', + endpoint: 'GET /internal/apm/services/{serviceName}/agent', params: { path: { serviceName }, query: { start, end }, diff --git a/x-pack/plugins/apm/public/context/apm_service/use_service_alerts_fetcher.tsx b/x-pack/plugins/apm/public/context/apm_service/use_service_alerts_fetcher.tsx index 8491cdfb3f5ebf..d0e1edc775a81b 100644 --- a/x-pack/plugins/apm/public/context/apm_service/use_service_alerts_fetcher.tsx +++ b/x-pack/plugins/apm/public/context/apm_service/use_service_alerts_fetcher.tsx @@ -41,7 +41,7 @@ export function useServiceAlertsFetcher({ } return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/alerts', + endpoint: 'GET /internal/apm/services/{serviceName}/alerts', params: { path: { serviceName, diff --git a/x-pack/plugins/apm/public/context/apm_service/use_service_transaction_types_fetcher.tsx b/x-pack/plugins/apm/public/context/apm_service/use_service_transaction_types_fetcher.tsx index c2e81cb0c92aef..e81a2d956bf3c4 100644 --- a/x-pack/plugins/apm/public/context/apm_service/use_service_transaction_types_fetcher.tsx +++ b/x-pack/plugins/apm/public/context/apm_service/use_service_transaction_types_fetcher.tsx @@ -22,7 +22,8 @@ export function useServiceTransactionTypesFetcher({ (callApmApi) => { if (serviceName && start && end) { return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/transaction_types', + endpoint: + 'GET /internal/apm/services/{serviceName}/transaction_types', params: { path: { serviceName }, query: { start, end }, diff --git a/x-pack/plugins/apm/public/hooks/use_dynamic_index_pattern.ts b/x-pack/plugins/apm/public/hooks/use_dynamic_index_pattern.ts index 9c637dc1336add..dc19af0a98cea5 100644 --- a/x-pack/plugins/apm/public/hooks/use_dynamic_index_pattern.ts +++ b/x-pack/plugins/apm/public/hooks/use_dynamic_index_pattern.ts @@ -10,7 +10,7 @@ import { useFetcher } from './use_fetcher'; export function useDynamicIndexPatternFetcher() { const { data, status } = useFetcher((callApmApi) => { return callApmApi({ - endpoint: 'GET /api/apm/index_pattern/dynamic', + endpoint: 'GET /internal/apm/index_pattern/dynamic', isCachable: true, }); }, []); diff --git a/x-pack/plugins/apm/public/hooks/use_environments_fetcher.tsx b/x-pack/plugins/apm/public/hooks/use_environments_fetcher.tsx index d6352b561c6417..e37677e806e8a7 100644 --- a/x-pack/plugins/apm/public/hooks/use_environments_fetcher.tsx +++ b/x-pack/plugins/apm/public/hooks/use_environments_fetcher.tsx @@ -38,7 +38,7 @@ export function useEnvironmentsFetcher({ (callApmApi) => { if (start && end) { return callApmApi({ - endpoint: 'GET /api/apm/environments', + endpoint: 'GET /internal/apm/environments', params: { query: { start, diff --git a/x-pack/plugins/apm/public/hooks/use_error_group_distribution_fetcher.tsx b/x-pack/plugins/apm/public/hooks/use_error_group_distribution_fetcher.tsx index 683a545cdd1252..120cbba952f3ef 100644 --- a/x-pack/plugins/apm/public/hooks/use_error_group_distribution_fetcher.tsx +++ b/x-pack/plugins/apm/public/hooks/use_error_group_distribution_fetcher.tsx @@ -30,7 +30,8 @@ export function useErrorGroupDistributionFetcher({ (callApmApi) => { if (start && end) { return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/errors/distribution', + endpoint: + 'GET /internal/apm/services/{serviceName}/errors/distribution', params: { path: { serviceName }, query: { diff --git a/x-pack/plugins/apm/public/hooks/use_fallback_to_transactions_fetcher.tsx b/x-pack/plugins/apm/public/hooks/use_fallback_to_transactions_fetcher.tsx index 35122bfef17491..3dfb02cec5fbcd 100644 --- a/x-pack/plugins/apm/public/hooks/use_fallback_to_transactions_fetcher.tsx +++ b/x-pack/plugins/apm/public/hooks/use_fallback_to_transactions_fetcher.tsx @@ -19,7 +19,7 @@ export function useFallbackToTransactionsFetcher({ kuery }: { kuery: string }) { const { data = { fallbackToTransactions: false } } = useFetcher( (callApmApi) => { return callApmApi({ - endpoint: 'GET /api/apm/fallback_to_transactions', + endpoint: 'GET /internal/apm/fallback_to_transactions', params: { query: { kuery, start, end }, }, diff --git a/x-pack/plugins/apm/public/hooks/use_service_metric_charts_fetcher.ts b/x-pack/plugins/apm/public/hooks/use_service_metric_charts_fetcher.ts index 82338d45a41332..ef360698192e1e 100644 --- a/x-pack/plugins/apm/public/hooks/use_service_metric_charts_fetcher.ts +++ b/x-pack/plugins/apm/public/hooks/use_service_metric_charts_fetcher.ts @@ -40,7 +40,7 @@ export function useServiceMetricChartsFetcher({ (callApmApi) => { if (serviceName && start && end && agentName) { return callApmApi({ - endpoint: 'GET /api/apm/services/{serviceName}/metrics/charts', + endpoint: 'GET /internal/apm/services/{serviceName}/metrics/charts', params: { path: { serviceName }, query: { diff --git a/x-pack/plugins/apm/public/hooks/use_transaction_latency_chart_fetcher.ts b/x-pack/plugins/apm/public/hooks/use_transaction_latency_chart_fetcher.ts index 660408700b4dfb..d44ec853a242cb 100644 --- a/x-pack/plugins/apm/public/hooks/use_transaction_latency_chart_fetcher.ts +++ b/x-pack/plugins/apm/public/hooks/use_transaction_latency_chart_fetcher.ts @@ -57,7 +57,7 @@ export function useTransactionLatencyChartsFetcher({ ) { return callApmApi({ endpoint: - 'GET /api/apm/services/{serviceName}/transactions/charts/latency', + 'GET /internal/apm/services/{serviceName}/transactions/charts/latency', params: { path: { serviceName }, query: { diff --git a/x-pack/plugins/apm/public/hooks/use_transaction_trace_samples_fetcher.ts b/x-pack/plugins/apm/public/hooks/use_transaction_trace_samples_fetcher.ts index 5279c7ce143fc7..48c2d555fd43b0 100644 --- a/x-pack/plugins/apm/public/hooks/use_transaction_trace_samples_fetcher.ts +++ b/x-pack/plugins/apm/public/hooks/use_transaction_trace_samples_fetcher.ts @@ -51,7 +51,7 @@ export function useTransactionTraceSamplesFetcher({ if (serviceName && start && end && transactionType && transactionName) { const response = await callApmApi({ endpoint: - 'GET /api/apm/services/{serviceName}/transactions/traces/samples', + 'GET /internal/apm/services/{serviceName}/transactions/traces/samples', params: { path: { serviceName, diff --git a/x-pack/plugins/apm/public/selectors/latency_chart_selectors.ts b/x-pack/plugins/apm/public/selectors/latency_chart_selectors.ts index 1fb4eb51dd770f..bb681430893471 100644 --- a/x-pack/plugins/apm/public/selectors/latency_chart_selectors.ts +++ b/x-pack/plugins/apm/public/selectors/latency_chart_selectors.ts @@ -14,7 +14,7 @@ import { APMChartSpec, Coordinate } from '../../typings/timeseries'; import { APIReturnType } from '../services/rest/createCallApmApi'; export type LatencyChartsResponse = - APIReturnType<'GET /api/apm/services/{serviceName}/transactions/charts/latency'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/charts/latency'>; export interface LatencyChartData { currentPeriod?: APMChartSpec; diff --git a/x-pack/plugins/apm/public/services/callApi.test.ts b/x-pack/plugins/apm/public/services/callApi.test.ts index 82be0bbf5dfcf4..85e58bc81a93f9 100644 --- a/x-pack/plugins/apm/public/services/callApi.test.ts +++ b/x-pack/plugins/apm/public/services/callApi.test.ts @@ -41,11 +41,14 @@ describe('callApi', () => { }); it('should add debug param for APM endpoints', async () => { - await callApi(core, { pathname: `/api/apm/status/server` }); - - expect(core.http.get).toHaveBeenCalledWith('/api/apm/status/server', { - query: { _inspect: true }, - }); + await callApi(core, { pathname: `/internal/apm/status/server` }); + + expect(core.http.get).toHaveBeenCalledWith( + '/internal/apm/status/server', + { + query: { _inspect: true }, + } + ); }); it('should not add debug param for non-APM endpoints', async () => { diff --git a/x-pack/plugins/apm/public/services/callApmApi.test.ts b/x-pack/plugins/apm/public/services/callApmApi.test.ts index 56146c49fc57dc..b1d31586c2ceea 100644 --- a/x-pack/plugins/apm/public/services/callApmApi.test.ts +++ b/x-pack/plugins/apm/public/services/callApmApi.test.ts @@ -24,7 +24,7 @@ describe('callApmApi', () => { it('should format the pathname with the given path params', async () => { await callApmApi({ - endpoint: 'GET /api/apm/{param1}/to/{param2}', + endpoint: 'GET /internal/apm/{param1}/to/{param2}', params: { path: { param1: 'foo', @@ -36,14 +36,14 @@ describe('callApmApi', () => { expect(callApi).toHaveBeenCalledWith( {}, expect.objectContaining({ - pathname: '/api/apm/foo/to/bar', + pathname: '/internal/apm/foo/to/bar', }) ); }); it('should add the query parameters to the options object', async () => { await callApmApi({ - endpoint: 'GET /api/apm', + endpoint: 'GET /internal/apm', params: { query: { foo: 'bar', @@ -55,7 +55,7 @@ describe('callApmApi', () => { expect(callApi).toHaveBeenCalledWith( {}, expect.objectContaining({ - pathname: '/api/apm', + pathname: '/internal/apm', query: { foo: 'bar', bar: 'foo', @@ -66,7 +66,7 @@ describe('callApmApi', () => { it('should stringify the body and add it to the options object', async () => { await callApmApi({ - endpoint: 'POST /api/apm', + endpoint: 'POST /internal/apm', params: { body: { foo: 'bar', @@ -78,7 +78,7 @@ describe('callApmApi', () => { expect(callApi).toHaveBeenCalledWith( {}, expect.objectContaining({ - pathname: '/api/apm', + pathname: '/internal/apm', method: 'post', body: { foo: 'bar', diff --git a/x-pack/plugins/apm/public/services/rest/apm_observability_overview_fetchers.ts b/x-pack/plugins/apm/public/services/rest/apm_observability_overview_fetchers.ts index 1b95c88a5fdc57..f26fd85bde9685 100644 --- a/x-pack/plugins/apm/public/services/rest/apm_observability_overview_fetchers.ts +++ b/x-pack/plugins/apm/public/services/rest/apm_observability_overview_fetchers.ts @@ -17,7 +17,7 @@ export const fetchObservabilityOverviewPageData = async ({ bucketSize, }: FetchDataParams): Promise => { const data = await callApmApi({ - endpoint: 'GET /api/apm/observability_overview', + endpoint: 'GET /internal/apm/observability_overview', signal: null, params: { query: { @@ -52,7 +52,7 @@ export const fetchObservabilityOverviewPageData = async ({ export async function getHasData() { return await callApmApi({ - endpoint: 'GET /api/apm/observability_overview/has_data', + endpoint: 'GET /internal/apm/observability_overview/has_data', signal: null, }); } diff --git a/x-pack/plugins/apm/public/services/rest/callApi.ts b/x-pack/plugins/apm/public/services/rest/callApi.ts index 53ddbed90413a9..9b6d0c383e9a7d 100644 --- a/x-pack/plugins/apm/public/services/rest/callApi.ts +++ b/x-pack/plugins/apm/public/services/rest/callApi.ts @@ -18,7 +18,7 @@ function fetchOptionsWithDebug( ) { const debugEnabled = inspectableEsQueriesEnabled && - startsWith(fetchOptions.pathname, '/api/apm'); + startsWith(fetchOptions.pathname, '/internal/apm'); const { body, ...rest } = fetchOptions; diff --git a/x-pack/plugins/apm/public/services/rest/index_pattern.ts b/x-pack/plugins/apm/public/services/rest/index_pattern.ts index 0bb5839759f64e..f250c514000ba4 100644 --- a/x-pack/plugins/apm/public/services/rest/index_pattern.ts +++ b/x-pack/plugins/apm/public/services/rest/index_pattern.ts @@ -9,7 +9,7 @@ import { callApmApi } from './createCallApmApi'; export const createStaticIndexPattern = async () => { return await callApmApi({ - endpoint: 'POST /api/apm/index_pattern/static', + endpoint: 'POST /internal/apm/index_pattern/static', signal: null, }); }; diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/config_agent.stories.tsx b/x-pack/plugins/apm/public/tutorial/config_agent/config_agent.stories.tsx index 166839390bc22c..7bebd89dc00210 100644 --- a/x-pack/plugins/apm/public/tutorial/config_agent/config_agent.stories.tsx +++ b/x-pack/plugins/apm/public/tutorial/config_agent/config_agent.stories.tsx @@ -12,7 +12,7 @@ import { POLICY_ELASTIC_AGENT_ON_CLOUD } from '../../../common/fleet'; import TutorialConfigAgent from './'; import { APIReturnType } from '../../services/rest/createCallApmApi'; -export type APIResponseType = APIReturnType<'GET /api/apm/fleet/agents'>; +export type APIResponseType = APIReturnType<'GET /internal/apm/fleet/agents'>; interface Args { apmAgent: string; diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/get_policy_options.test.ts b/x-pack/plugins/apm/public/tutorial/config_agent/get_policy_options.test.ts index c6dc7265f3d3e6..79eefeab85c632 100644 --- a/x-pack/plugins/apm/public/tutorial/config_agent/get_policy_options.test.ts +++ b/x-pack/plugins/apm/public/tutorial/config_agent/get_policy_options.test.ts @@ -7,7 +7,7 @@ import { getPolicyOptions } from './get_policy_options'; import { APIReturnType } from '../../services/rest/createCallApmApi'; -type APIResponseType = APIReturnType<'GET /api/apm/fleet/agents'>; +type APIResponseType = APIReturnType<'GET /internal/apm/fleet/agents'>; const policyElasticAgentOnCloudAgent = { id: 'policy-elastic-agent-on-cloud', diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/index.tsx b/x-pack/plugins/apm/public/tutorial/config_agent/index.tsx index cfb51b4cd3b680..5ff1fd7f42119d 100644 --- a/x-pack/plugins/apm/public/tutorial/config_agent/index.tsx +++ b/x-pack/plugins/apm/public/tutorial/config_agent/index.tsx @@ -21,7 +21,7 @@ import { CopyCommands } from './copy_commands'; import { getPolicyOptions, PolicyOption } from './get_policy_options'; import { PolicySelector } from './policy_selector'; -export type APIResponseType = APIReturnType<'GET /api/apm/fleet/agents'>; +export type APIResponseType = APIReturnType<'GET /internal/apm/fleet/agents'>; const CentralizedContainer = styled.div` display: flex; @@ -90,7 +90,7 @@ function TutorialConfigAgent({ async function fetchData() { setIsLoading(true); try { - const response = await http.get('/api/apm/fleet/agents'); + const response = await http.get('/internal/apm/fleet/agents'); if (response) { setData(response as APIResponseType); } diff --git a/x-pack/plugins/apm/public/tutorial/tutorial_apm_fleet_check.ts b/x-pack/plugins/apm/public/tutorial/tutorial_apm_fleet_check.ts index 8db8614d606a9e..8502689724d04f 100644 --- a/x-pack/plugins/apm/public/tutorial/tutorial_apm_fleet_check.ts +++ b/x-pack/plugins/apm/public/tutorial/tutorial_apm_fleet_check.ts @@ -9,7 +9,7 @@ import { callApmApi } from '../services/rest/createCallApmApi'; export async function hasFleetApmIntegrations() { try { const { hasData = false } = await callApmApi({ - endpoint: 'GET /api/apm/fleet/has_data', + endpoint: 'GET /internal/apm/fleet/has_data', signal: null, }); return hasData; diff --git a/x-pack/plugins/apm/public/tutorial/tutorial_fleet_instructions/index.tsx b/x-pack/plugins/apm/public/tutorial/tutorial_fleet_instructions/index.tsx index 175d6797bb29f1..f0d6dc72b72a54 100644 --- a/x-pack/plugins/apm/public/tutorial/tutorial_fleet_instructions/index.tsx +++ b/x-pack/plugins/apm/public/tutorial/tutorial_fleet_instructions/index.tsx @@ -29,7 +29,7 @@ const CentralizedContainer = styled.div` align-items: center; `; -type APIResponseType = APIReturnType<'GET /api/apm/fleet/has_data'>; +type APIResponseType = APIReturnType<'GET /internal/apm/fleet/has_data'>; function TutorialFleetInstructions({ http, basePath, isDarkTheme }: Props) { const [data, setData] = useState(); @@ -39,7 +39,7 @@ function TutorialFleetInstructions({ http, basePath, isDarkTheme }: Props) { async function fetchData() { setIsLoading(true); try { - const response = await http.get('/api/apm/fleet/has_data'); + const response = await http.get('/internal/apm/fleet/has_data'); setData(response as APIResponseType); } catch (e) { setIsLoading(false); diff --git a/x-pack/plugins/apm/server/routes/alerts/chart_preview.ts b/x-pack/plugins/apm/server/routes/alerts/chart_preview.ts index 012cf304aa3cea..23a794bb7976a3 100644 --- a/x-pack/plugins/apm/server/routes/alerts/chart_preview.ts +++ b/x-pack/plugins/apm/server/routes/alerts/chart_preview.ts @@ -34,7 +34,7 @@ const alertParamsRt = t.intersection([ export type AlertParams = t.TypeOf; const transactionErrorRateChartPreview = createApmServerRoute({ - endpoint: 'GET /api/apm/alerts/chart_preview/transaction_error_rate', + endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_error_rate', params: t.type({ query: alertParamsRt }), options: { tags: ['access:apm'] }, handler: async (resources) => { @@ -52,7 +52,7 @@ const transactionErrorRateChartPreview = createApmServerRoute({ }); const transactionErrorCountChartPreview = createApmServerRoute({ - endpoint: 'GET /api/apm/alerts/chart_preview/transaction_error_count', + endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_error_count', params: t.type({ query: alertParamsRt }), options: { tags: ['access:apm'] }, handler: async (resources) => { @@ -71,7 +71,7 @@ const transactionErrorCountChartPreview = createApmServerRoute({ }); const transactionDurationChartPreview = createApmServerRoute({ - endpoint: 'GET /api/apm/alerts/chart_preview/transaction_duration', + endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_duration', params: t.type({ query: alertParamsRt }), options: { tags: ['access:apm'] }, handler: async (resources) => { diff --git a/x-pack/plugins/apm/server/routes/backends.ts b/x-pack/plugins/apm/server/routes/backends.ts index 7aabfb32991342..feb4ca8bb978ce 100644 --- a/x-pack/plugins/apm/server/routes/backends.ts +++ b/x-pack/plugins/apm/server/routes/backends.ts @@ -19,7 +19,7 @@ import { getThroughputChartsForBackend } from '../lib/backends/get_throughput_ch import { getErrorRateChartsForBackend } from '../lib/backends/get_error_rate_charts_for_backend'; const topBackendsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/backends/top_backends', + endpoint: 'GET /internal/apm/backends/top_backends', params: t.intersection([ t.type({ query: t.intersection([ @@ -65,7 +65,7 @@ const topBackendsRoute = createApmServerRoute({ }); const upstreamServicesForBackendRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/backends/{backendName}/upstream_services', + endpoint: 'GET /internal/apm/backends/{backendName}/upstream_services', params: t.intersection([ t.type({ path: t.type({ @@ -121,7 +121,7 @@ const upstreamServicesForBackendRoute = createApmServerRoute({ }); const backendMetadataRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/backends/{backendName}/metadata', + endpoint: 'GET /internal/apm/backends/{backendName}/metadata', params: t.type({ path: t.type({ backendName: t.string, @@ -150,7 +150,7 @@ const backendMetadataRoute = createApmServerRoute({ }); const backendLatencyChartsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/backends/{backendName}/charts/latency', + endpoint: 'GET /internal/apm/backends/{backendName}/charts/latency', params: t.type({ path: t.type({ backendName: t.string, @@ -193,7 +193,7 @@ const backendLatencyChartsRoute = createApmServerRoute({ }); const backendThroughputChartsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/backends/{backendName}/charts/throughput', + endpoint: 'GET /internal/apm/backends/{backendName}/charts/throughput', params: t.type({ path: t.type({ backendName: t.string, @@ -236,7 +236,7 @@ const backendThroughputChartsRoute = createApmServerRoute({ }); const backendFailedTransactionRateChartsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/backends/{backendName}/charts/error_rate', + endpoint: 'GET /internal/apm/backends/{backendName}/charts/error_rate', params: t.type({ path: t.type({ backendName: t.string, diff --git a/x-pack/plugins/apm/server/routes/environments.ts b/x-pack/plugins/apm/server/routes/environments.ts index 4b00320009e27b..59e75f6f9c3411 100644 --- a/x-pack/plugins/apm/server/routes/environments.ts +++ b/x-pack/plugins/apm/server/routes/environments.ts @@ -15,7 +15,7 @@ import { createApmServerRoute } from './create_apm_server_route'; import { createApmServerRouteRepository } from './create_apm_server_route_repository'; const environmentsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/environments', + endpoint: 'GET /internal/apm/environments', params: t.type({ query: t.intersection([ t.partial({ diff --git a/x-pack/plugins/apm/server/routes/errors.ts b/x-pack/plugins/apm/server/routes/errors.ts index 9a4199e319494f..0864276b67fee8 100644 --- a/x-pack/plugins/apm/server/routes/errors.ts +++ b/x-pack/plugins/apm/server/routes/errors.ts @@ -15,7 +15,7 @@ import { environmentRt, kueryRt, rangeRt } from './default_api_types'; import { createApmServerRouteRepository } from './create_apm_server_route_repository'; const errorsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/errors', + endpoint: 'GET /internal/apm/services/{serviceName}/errors', params: t.type({ path: t.type({ serviceName: t.string, @@ -54,7 +54,7 @@ const errorsRoute = createApmServerRoute({ }); const errorGroupsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/errors/{groupId}', + endpoint: 'GET /internal/apm/services/{serviceName}/errors/{groupId}', params: t.type({ path: t.type({ serviceName: t.string, @@ -82,7 +82,7 @@ const errorGroupsRoute = createApmServerRoute({ }); const errorDistributionRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/errors/distribution', + endpoint: 'GET /internal/apm/services/{serviceName}/errors/distribution', params: t.type({ path: t.type({ serviceName: t.string, diff --git a/x-pack/plugins/apm/server/routes/event_metadata.ts b/x-pack/plugins/apm/server/routes/event_metadata.ts index 8970ab8ffdeeac..00241d2ef1c689 100644 --- a/x-pack/plugins/apm/server/routes/event_metadata.ts +++ b/x-pack/plugins/apm/server/routes/event_metadata.ts @@ -13,7 +13,7 @@ import { processorEventRt } from '../../common/processor_event'; import { setupRequest } from '../lib/helpers/setup_request'; const eventMetadataRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/event_metadata/{processorEvent}/{id}', + endpoint: 'GET /internal/apm/event_metadata/{processorEvent}/{id}', options: { tags: ['access:apm'] }, params: t.type({ path: t.type({ diff --git a/x-pack/plugins/apm/server/routes/fallback_to_transactions.ts b/x-pack/plugins/apm/server/routes/fallback_to_transactions.ts index 8f30b9c0898212..ba74cc0b7a88ae 100644 --- a/x-pack/plugins/apm/server/routes/fallback_to_transactions.ts +++ b/x-pack/plugins/apm/server/routes/fallback_to_transactions.ts @@ -13,7 +13,7 @@ import { createApmServerRouteRepository } from './create_apm_server_route_reposi import { kueryRt, rangeRt } from './default_api_types'; const fallbackToTransactionsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/fallback_to_transactions', + endpoint: 'GET /internal/apm/fallback_to_transactions', params: t.partial({ query: t.intersection([kueryRt, t.partial(rangeRt.props)]), }), diff --git a/x-pack/plugins/apm/server/routes/fleet.ts b/x-pack/plugins/apm/server/routes/fleet.ts index 5bfbfef5e6800f..d8097228df0dc9 100644 --- a/x-pack/plugins/apm/server/routes/fleet.ts +++ b/x-pack/plugins/apm/server/routes/fleet.ts @@ -28,7 +28,7 @@ import { createApmServerRoute } from './create_apm_server_route'; import { createApmServerRouteRepository } from './create_apm_server_route_repository'; const hasFleetDataRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/fleet/has_data', + endpoint: 'GET /internal/apm/fleet/has_data', options: { tags: [] }, handler: async ({ core, plugins }) => { const fleetPluginStart = await plugins.fleet?.start(); @@ -44,7 +44,7 @@ const hasFleetDataRoute = createApmServerRoute({ }); const fleetAgentsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/fleet/agents', + endpoint: 'GET /internal/apm/fleet/agents', options: { tags: [] }, handler: async ({ core, plugins }) => { const cloudSetup = plugins.cloud?.setup; @@ -92,7 +92,7 @@ const fleetAgentsRoute = createApmServerRoute({ }); const saveApmServerSchemaRoute = createApmServerRoute({ - endpoint: 'POST /api/apm/fleet/apm_server_schema', + endpoint: 'POST /internal/apm/fleet/apm_server_schema', options: { tags: ['access:apm', 'access:apm_write'] }, params: t.type({ body: t.type({ @@ -113,7 +113,7 @@ const saveApmServerSchemaRoute = createApmServerRoute({ }); const getUnsupportedApmServerSchemaRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/fleet/apm_server_schema/unsupported', + endpoint: 'GET /internal/apm/fleet/apm_server_schema/unsupported', options: { tags: ['access:apm'] }, handler: async (resources) => { const { context } = resources; @@ -125,7 +125,7 @@ const getUnsupportedApmServerSchemaRoute = createApmServerRoute({ }); const getMigrationCheckRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/fleet/migration_check', + endpoint: 'GET /internal/apm/fleet/migration_check', options: { tags: ['access:apm'] }, handler: async (resources) => { const { plugins, context, config, request } = resources; @@ -154,7 +154,7 @@ const getMigrationCheckRoute = createApmServerRoute({ }); const createCloudApmPackagePolicyRoute = createApmServerRoute({ - endpoint: 'POST /api/apm/fleet/cloud_apm_package_policy', + endpoint: 'POST /internal/apm/fleet/cloud_apm_package_policy', options: { tags: ['access:apm', 'access:apm_write'] }, handler: async (resources) => { const { plugins, context, config, request, logger } = resources; diff --git a/x-pack/plugins/apm/server/routes/historical_data/index.ts b/x-pack/plugins/apm/server/routes/historical_data/index.ts index be3fd29d14b9dd..fb67dc4f5b649e 100644 --- a/x-pack/plugins/apm/server/routes/historical_data/index.ts +++ b/x-pack/plugins/apm/server/routes/historical_data/index.ts @@ -11,7 +11,7 @@ import { createApmServerRouteRepository } from '../create_apm_server_route_repos import { hasHistoricalAgentData } from './has_historical_agent_data'; const hasDataRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/has_data', + endpoint: 'GET /internal/apm/has_data', options: { tags: ['access:apm'] }, handler: async (resources) => { const setup = await setupRequest(resources); diff --git a/x-pack/plugins/apm/server/routes/index_pattern.ts b/x-pack/plugins/apm/server/routes/index_pattern.ts index c957e828bf12a3..a996636ae56a1e 100644 --- a/x-pack/plugins/apm/server/routes/index_pattern.ts +++ b/x-pack/plugins/apm/server/routes/index_pattern.ts @@ -12,7 +12,7 @@ import { getDynamicIndexPattern } from '../lib/index_pattern/get_dynamic_index_p import { createApmServerRoute } from './create_apm_server_route'; const staticIndexPatternRoute = createApmServerRoute({ - endpoint: 'POST /api/apm/index_pattern/static', + endpoint: 'POST /internal/apm/index_pattern/static', options: { tags: ['access:apm'] }, handler: async (resources) => { const { @@ -43,7 +43,7 @@ const staticIndexPatternRoute = createApmServerRoute({ }); const dynamicIndexPatternRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/index_pattern/dynamic', + endpoint: 'GET /internal/apm/index_pattern/dynamic', options: { tags: ['access:apm'] }, handler: async ({ context, config, logger }) => { const dynamicIndexPattern = await getDynamicIndexPattern({ diff --git a/x-pack/plugins/apm/server/routes/metrics.ts b/x-pack/plugins/apm/server/routes/metrics.ts index ea4878016652f8..8b6b16a26f1d84 100644 --- a/x-pack/plugins/apm/server/routes/metrics.ts +++ b/x-pack/plugins/apm/server/routes/metrics.ts @@ -13,7 +13,7 @@ import { createApmServerRouteRepository } from './create_apm_server_route_reposi import { environmentRt, kueryRt, rangeRt } from './default_api_types'; const metricsChartsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/metrics/charts', + endpoint: 'GET /internal/apm/services/{serviceName}/metrics/charts', params: t.type({ path: t.type({ serviceName: t.string, diff --git a/x-pack/plugins/apm/server/routes/observability_overview.ts b/x-pack/plugins/apm/server/routes/observability_overview.ts index feaa6b580dac70..a99291ff32bb6d 100644 --- a/x-pack/plugins/apm/server/routes/observability_overview.ts +++ b/x-pack/plugins/apm/server/routes/observability_overview.ts @@ -17,7 +17,7 @@ import { createApmServerRouteRepository } from './create_apm_server_route_reposi import { createApmServerRoute } from './create_apm_server_route'; const observabilityOverviewHasDataRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/observability_overview/has_data', + endpoint: 'GET /internal/apm/observability_overview/has_data', options: { tags: ['access:apm'] }, handler: async (resources) => { const setup = await setupRequest(resources); @@ -26,7 +26,7 @@ const observabilityOverviewHasDataRoute = createApmServerRoute({ }); const observabilityOverviewRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/observability_overview', + endpoint: 'GET /internal/apm/observability_overview', params: t.type({ query: t.intersection([rangeRt, t.type({ bucketSize: t.string })]), }), diff --git a/x-pack/plugins/apm/server/routes/service_map.ts b/x-pack/plugins/apm/server/routes/service_map.ts index 8fb3abe99e36c9..f9062ac13e0492 100644 --- a/x-pack/plugins/apm/server/routes/service_map.ts +++ b/x-pack/plugins/apm/server/routes/service_map.ts @@ -20,7 +20,7 @@ import { createApmServerRouteRepository } from './create_apm_server_route_reposi import { environmentRt, rangeRt } from './default_api_types'; const serviceMapRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/service-map', + endpoint: 'GET /internal/apm/service-map', params: t.type({ query: t.intersection([ t.partial({ @@ -70,7 +70,7 @@ const serviceMapRoute = createApmServerRoute({ }); const serviceMapServiceNodeRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/service-map/service/{serviceName}', + endpoint: 'GET /internal/apm/service-map/service/{serviceName}', params: t.type({ path: t.type({ serviceName: t.string, @@ -114,7 +114,7 @@ const serviceMapServiceNodeRoute = createApmServerRoute({ }); const serviceMapBackendNodeRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/service-map/backend/{backendName}', + endpoint: 'GET /internal/apm/service-map/backend/{backendName}', params: t.type({ path: t.type({ backendName: t.string, diff --git a/x-pack/plugins/apm/server/routes/service_nodes.ts b/x-pack/plugins/apm/server/routes/service_nodes.ts index 4bd1c93599723a..2081b794f8ab17 100644 --- a/x-pack/plugins/apm/server/routes/service_nodes.ts +++ b/x-pack/plugins/apm/server/routes/service_nodes.ts @@ -14,7 +14,7 @@ import { rangeRt, kueryRt } from './default_api_types'; import { environmentRt } from '../../common/environment_rt'; const serviceNodesRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/serviceNodes', + endpoint: 'GET /internal/apm/services/{serviceName}/serviceNodes', params: t.type({ path: t.type({ serviceName: t.string, diff --git a/x-pack/plugins/apm/server/routes/services.ts b/x-pack/plugins/apm/server/routes/services.ts index a612575d16ff6e..d4af7315b9c231 100644 --- a/x-pack/plugins/apm/server/routes/services.ts +++ b/x-pack/plugins/apm/server/routes/services.ts @@ -48,7 +48,7 @@ import { getServiceDependenciesBreakdown } from '../lib/services/get_service_dep import { getBucketSizeForAggregatedTransactions } from '../lib/helpers/get_bucket_size_for_aggregated_transactions'; const servicesRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services', + endpoint: 'GET /internal/apm/services', params: t.type({ query: t.intersection([environmentRt, kueryRt, rangeRt]), }), @@ -75,7 +75,7 @@ const servicesRoute = createApmServerRoute({ }); const servicesDetailedStatisticsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/detailed_statistics', + endpoint: 'GET /internal/apm/services/detailed_statistics', params: t.type({ query: t.intersection([ environmentRt, @@ -116,7 +116,7 @@ const servicesDetailedStatisticsRoute = createApmServerRoute({ }); const serviceMetadataDetailsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/metadata/details', + endpoint: 'GET /internal/apm/services/{serviceName}/metadata/details', params: t.type({ path: t.type({ serviceName: t.string }), query: rangeRt, @@ -147,7 +147,7 @@ const serviceMetadataDetailsRoute = createApmServerRoute({ }); const serviceMetadataIconsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/metadata/icons', + endpoint: 'GET /internal/apm/services/{serviceName}/metadata/icons', params: t.type({ path: t.type({ serviceName: t.string }), query: rangeRt, @@ -178,7 +178,7 @@ const serviceMetadataIconsRoute = createApmServerRoute({ }); const serviceAgentRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/agent', + endpoint: 'GET /internal/apm/services/{serviceName}/agent', params: t.type({ path: t.type({ serviceName: t.string, @@ -211,7 +211,7 @@ const serviceAgentRoute = createApmServerRoute({ }); const serviceTransactionTypesRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/transaction_types', + endpoint: 'GET /internal/apm/services/{serviceName}/transaction_types', params: t.type({ path: t.type({ serviceName: t.string, @@ -243,7 +243,7 @@ const serviceTransactionTypesRoute = createApmServerRoute({ const serviceNodeMetadataRoute = createApmServerRoute({ endpoint: - 'GET /api/apm/services/{serviceName}/node/{serviceNodeName}/metadata', + 'GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata', params: t.type({ path: t.type({ serviceName: t.string, @@ -383,7 +383,8 @@ const serviceAnnotationsCreateRoute = createApmServerRoute({ }); const serviceErrorGroupsMainStatisticsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/error_groups/main_statistics', + endpoint: + 'GET /internal/apm/services/{serviceName}/error_groups/main_statistics', params: t.type({ path: t.type({ serviceName: t.string, @@ -420,7 +421,7 @@ const serviceErrorGroupsMainStatisticsRoute = createApmServerRoute({ const serviceErrorGroupsDetailedStatisticsRoute = createApmServerRoute({ endpoint: - 'GET /api/apm/services/{serviceName}/error_groups/detailed_statistics', + 'GET /internal/apm/services/{serviceName}/error_groups/detailed_statistics', params: t.type({ path: t.type({ serviceName: t.string, @@ -474,7 +475,7 @@ const serviceErrorGroupsDetailedStatisticsRoute = createApmServerRoute({ }); const serviceThroughputRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/throughput', + endpoint: 'GET /internal/apm/services/{serviceName}/throughput', params: t.type({ path: t.type({ serviceName: t.string, @@ -556,7 +557,7 @@ const serviceThroughputRoute = createApmServerRoute({ const serviceInstancesMainStatisticsRoute = createApmServerRoute({ endpoint: - 'GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics', + 'GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics', params: t.type({ path: t.type({ serviceName: t.string, @@ -630,7 +631,7 @@ const serviceInstancesMainStatisticsRoute = createApmServerRoute({ const serviceInstancesDetailedStatisticsRoute = createApmServerRoute({ endpoint: - 'GET /api/apm/services/{serviceName}/service_overview_instances/detailed_statistics', + 'GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics', params: t.type({ path: t.type({ serviceName: t.string, @@ -693,7 +694,7 @@ const serviceInstancesDetailedStatisticsRoute = createApmServerRoute({ export const serviceInstancesMetadataDetails = createApmServerRoute({ endpoint: - 'GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}', + 'GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}', params: t.type({ path: t.type({ serviceName: t.string, @@ -718,7 +719,7 @@ export const serviceInstancesMetadataDetails = createApmServerRoute({ }); export const serviceDependenciesRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/dependencies', + endpoint: 'GET /internal/apm/services/{serviceName}/dependencies', params: t.type({ path: t.type({ serviceName: t.string, @@ -773,7 +774,7 @@ export const serviceDependenciesRoute = createApmServerRoute({ }); export const serviceDependenciesBreakdownRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/dependencies/breakdown', + endpoint: 'GET /internal/apm/services/{serviceName}/dependencies/breakdown', params: t.type({ path: t.type({ serviceName: t.string, @@ -805,7 +806,7 @@ export const serviceDependenciesBreakdownRoute = createApmServerRoute({ }); const serviceProfilingTimelineRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/profiling/timeline', + endpoint: 'GET /internal/apm/services/{serviceName}/profiling/timeline', params: t.type({ path: t.type({ serviceName: t.string, @@ -837,7 +838,7 @@ const serviceProfilingTimelineRoute = createApmServerRoute({ }); const serviceProfilingStatisticsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/profiling/statistics', + endpoint: 'GET /internal/apm/services/{serviceName}/profiling/statistics', params: t.type({ path: t.type({ serviceName: t.string, @@ -886,7 +887,7 @@ const serviceProfilingStatisticsRoute = createApmServerRoute({ }); const serviceAlertsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/alerts', + endpoint: 'GET /internal/apm/services/{serviceName}/alerts', params: t.type({ path: t.type({ serviceName: t.string, @@ -922,7 +923,7 @@ const serviceAlertsRoute = createApmServerRoute({ }); const serviceInfrastructureRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/infrastructure', + endpoint: 'GET /internal/apm/services/{serviceName}/infrastructure', params: t.type({ path: t.type({ serviceName: t.string, diff --git a/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts b/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts index c7e45eb8c32e57..78db4e0c14b36f 100644 --- a/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts +++ b/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts @@ -23,7 +23,7 @@ import { createApmServerRouteRepository } from '../create_apm_server_route_repos // get ML anomaly detection jobs for each environment const anomalyDetectionJobsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/settings/anomaly-detection/jobs', + endpoint: 'GET /internal/apm/settings/anomaly-detection/jobs', options: { tags: ['access:apm', 'access:ml:canGetJobs'], }, @@ -51,7 +51,7 @@ const anomalyDetectionJobsRoute = createApmServerRoute({ // create new ML anomaly detection jobs for each given environment const createAnomalyDetectionJobsRoute = createApmServerRoute({ - endpoint: 'POST /api/apm/settings/anomaly-detection/jobs', + endpoint: 'POST /internal/apm/settings/anomaly-detection/jobs', options: { tags: ['access:apm', 'access:apm_write', 'access:ml:canCreateJob'], }, @@ -83,7 +83,7 @@ const createAnomalyDetectionJobsRoute = createApmServerRoute({ // get all available environments to create anomaly detection jobs for const anomalyDetectionEnvironmentsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/settings/anomaly-detection/environments', + endpoint: 'GET /internal/apm/settings/anomaly-detection/environments', options: { tags: ['access:apm'] }, handler: async (resources) => { const setup = await setupRequest(resources); diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices.ts b/x-pack/plugins/apm/server/routes/settings/apm_indices.ts index 003471aa89f39d..1cba5f972c27e7 100644 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices.ts +++ b/x-pack/plugins/apm/server/routes/settings/apm_indices.ts @@ -16,7 +16,7 @@ import { saveApmIndices } from '../../lib/settings/apm_indices/save_apm_indices' // get list of apm indices and values const apmIndexSettingsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/settings/apm-index-settings', + endpoint: 'GET /internal/apm/settings/apm-index-settings', options: { tags: ['access:apm'] }, handler: async ({ config, context }) => { const apmIndexSettings = await getApmIndexSettings({ config, context }); @@ -26,7 +26,7 @@ const apmIndexSettingsRoute = createApmServerRoute({ // get apm indices configuration object const apmIndicesRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/settings/apm-indices', + endpoint: 'GET /internal/apm/settings/apm-indices', options: { tags: ['access:apm'] }, handler: async (resources) => { const { context, config } = resources; @@ -39,7 +39,7 @@ const apmIndicesRoute = createApmServerRoute({ // save ui indices const saveApmIndicesRoute = createApmServerRoute({ - endpoint: 'POST /api/apm/settings/apm-indices/save', + endpoint: 'POST /internal/apm/settings/apm-indices/save', options: { tags: ['access:apm', 'access:apm_write'], }, diff --git a/x-pack/plugins/apm/server/routes/settings/custom_link.ts b/x-pack/plugins/apm/server/routes/settings/custom_link.ts index c9c5d236c14f90..af880898176bbd 100644 --- a/x-pack/plugins/apm/server/routes/settings/custom_link.ts +++ b/x-pack/plugins/apm/server/routes/settings/custom_link.ts @@ -25,7 +25,7 @@ import { createApmServerRoute } from '../create_apm_server_route'; import { createApmServerRouteRepository } from '../create_apm_server_route_repository'; const customLinkTransactionRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/settings/custom_links/transaction', + endpoint: 'GET /internal/apm/settings/custom_links/transaction', options: { tags: ['access:apm'] }, params: t.partial({ query: filterOptionsRt, @@ -41,7 +41,7 @@ const customLinkTransactionRoute = createApmServerRoute({ }); const listCustomLinksRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/settings/custom_links', + endpoint: 'GET /internal/apm/settings/custom_links', options: { tags: ['access:apm'] }, params: t.partial({ query: filterOptionsRt, @@ -63,7 +63,7 @@ const listCustomLinksRoute = createApmServerRoute({ }); const createCustomLinkRoute = createApmServerRoute({ - endpoint: 'POST /api/apm/settings/custom_links', + endpoint: 'POST /internal/apm/settings/custom_links', params: t.type({ body: payloadRt, }), @@ -86,7 +86,7 @@ const createCustomLinkRoute = createApmServerRoute({ }); const updateCustomLinkRoute = createApmServerRoute({ - endpoint: 'PUT /api/apm/settings/custom_links/{id}', + endpoint: 'PUT /internal/apm/settings/custom_links/{id}', params: t.type({ path: t.type({ id: t.string, @@ -116,7 +116,7 @@ const updateCustomLinkRoute = createApmServerRoute({ }); const deleteCustomLinkRoute = createApmServerRoute({ - endpoint: 'DELETE /api/apm/settings/custom_links/{id}', + endpoint: 'DELETE /internal/apm/settings/custom_links/{id}', params: t.type({ path: t.type({ id: t.string, diff --git a/x-pack/plugins/apm/server/routes/traces.ts b/x-pack/plugins/apm/server/routes/traces.ts index 52aa507bb38b16..a71b7eefeed3fe 100644 --- a/x-pack/plugins/apm/server/routes/traces.ts +++ b/x-pack/plugins/apm/server/routes/traces.ts @@ -17,7 +17,7 @@ import { createApmServerRouteRepository } from './create_apm_server_route_reposi import { getTransaction } from '../lib/transactions/get_transaction'; const tracesRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/traces', + endpoint: 'GET /internal/apm/traces', params: t.type({ query: t.intersection([environmentRt, kueryRt, rangeRt]), }), @@ -41,7 +41,7 @@ const tracesRoute = createApmServerRoute({ }); const tracesByIdRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/traces/{traceId}', + endpoint: 'GET /internal/apm/traces/{traceId}', params: t.type({ path: t.type({ traceId: t.string, @@ -60,7 +60,7 @@ const tracesByIdRoute = createApmServerRoute({ }); const rootTransactionByTraceIdRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/traces/{traceId}/root_transaction', + endpoint: 'GET /internal/apm/traces/{traceId}/root_transaction', params: t.type({ path: t.type({ traceId: t.string, @@ -76,7 +76,7 @@ const rootTransactionByTraceIdRoute = createApmServerRoute({ }); const transactionByIdRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/transactions/{transactionId}', + endpoint: 'GET /internal/apm/transactions/{transactionId}', params: t.type({ path: t.type({ transactionId: t.string, diff --git a/x-pack/plugins/apm/server/routes/transactions.ts b/x-pack/plugins/apm/server/routes/transactions.ts index a8d5c116990938..0e24d64d8c6c7f 100644 --- a/x-pack/plugins/apm/server/routes/transactions.ts +++ b/x-pack/plugins/apm/server/routes/transactions.ts @@ -31,7 +31,7 @@ import { const transactionGroupsMainStatisticsRoute = createApmServerRoute({ endpoint: - 'GET /api/apm/services/{serviceName}/transactions/groups/main_statistics', + 'GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics', params: t.type({ path: t.type({ serviceName: t.string }), query: t.intersection([ @@ -85,7 +85,7 @@ const transactionGroupsMainStatisticsRoute = createApmServerRoute({ const transactionGroupsDetailedStatisticsRoute = createApmServerRoute({ endpoint: - 'GET /api/apm/services/{serviceName}/transactions/groups/detailed_statistics', + 'GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics', params: t.type({ path: t.type({ serviceName: t.string }), query: t.intersection([ @@ -150,7 +150,8 @@ const transactionGroupsDetailedStatisticsRoute = createApmServerRoute({ }); const transactionLatencyChartsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/transactions/charts/latency', + endpoint: + 'GET /internal/apm/services/{serviceName}/transactions/charts/latency', params: t.type({ path: t.type({ serviceName: t.string, @@ -227,7 +228,8 @@ const transactionLatencyChartsRoute = createApmServerRoute({ }); const transactionTraceSamplesRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/transactions/traces/samples', + endpoint: + 'GET /internal/apm/services/{serviceName}/transactions/traces/samples', params: t.type({ path: t.type({ serviceName: t.string, @@ -284,7 +286,8 @@ const transactionTraceSamplesRoute = createApmServerRoute({ }); const transactionChartsBreakdownRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/services/{serviceName}/transaction/charts/breakdown', + endpoint: + 'GET /internal/apm/services/{serviceName}/transaction/charts/breakdown', params: t.type({ path: t.type({ serviceName: t.string, @@ -321,7 +324,7 @@ const transactionChartsBreakdownRoute = createApmServerRoute({ const transactionChartsErrorRateRoute = createApmServerRoute({ endpoint: - 'GET /api/apm/services/{serviceName}/transactions/charts/error_rate', + 'GET /internal/apm/services/{serviceName}/transactions/charts/error_rate', params: t.type({ path: t.type({ serviceName: t.string, diff --git a/x-pack/plugins/canvas/types/state.ts b/x-pack/plugins/canvas/types/state.ts index 30ded5f2a9c7e7..a3c770f12f2254 100644 --- a/x-pack/plugins/canvas/types/state.ts +++ b/x-pack/plugins/canvas/types/state.ts @@ -7,10 +7,10 @@ import { KibanaContext } from 'src/plugins/data/common'; import { + AnyExpressionFunctionDefinition, Datatable, ExpressionValueFilter, ExpressionImage, - ExpressionFunction, PointSeries, Render, Style, @@ -34,7 +34,7 @@ export interface AppState { interface StoreAppState { basePath: string; - serverFunctions: ExpressionFunction[]; + serverFunctions: AnyExpressionFunctionDefinition[]; ready: boolean; } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_logic.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_logic.test.tsx index bf64101527fd29..4248eb62e33f15 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_logic.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_logic.test.tsx @@ -45,6 +45,7 @@ const MOCK_RESPONSE: SuggestionsAPIResponse = { updated_at: '2021-07-08T14:35:50Z', promoted: ['1', '2'], status: 'applied', + operation: 'create', }, ], }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_table.tsx index 2a252a9666ac1f..b7a731c1654caf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_table.tsx @@ -68,7 +68,7 @@ const columns: Array> = [ field: 'promoted', name: i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.suggestionsTable.column.promotedDocumentsTableHeader', - { defaultMessage: 'Promoted documents' } + { defaultMessage: 'Promoted results' } ), render: (promoted: string[]) => {promoted.length}, }, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/constants.ts index 01ca80776ae85d..73e085ff83c515 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/constants.ts @@ -34,11 +34,11 @@ export const QUERY_INPUTS_PLACEHOLDER = i18n.translate( { defaultMessage: 'Enter a query' } ); -export const DELETE_MESSAGE = i18n.translate( +export const DELETE_CONFIRMATION_MESSAGE = i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.deleteConfirmation', { defaultMessage: 'Are you sure you want to remove this curation?' } ); -export const SUCCESS_MESSAGE = i18n.translate( +export const DELETE_SUCCESS_MESSAGE = i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.deleteSuccessMessage', { defaultMessage: 'Your curation was deleted' } ); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.test.tsx index 55725bb130deb2..2cee5bbbec80b0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.test.tsx @@ -14,7 +14,7 @@ import React from 'react'; import { shallow, ShallowWrapper } from 'enzyme'; -import { EuiBadge, EuiTab } from '@elastic/eui'; +import { EuiBadge, EuiButton, EuiLoadingSpinner, EuiTab } from '@elastic/eui'; import { getPageHeaderActions, getPageHeaderTabs, getPageTitle } from '../../../../test_helpers'; @@ -25,6 +25,7 @@ import { AppSearchPageTemplate } from '../../layout'; import { AutomatedCuration } from './automated_curation'; import { CurationLogic } from './curation_logic'; +import { DeleteCurationButton } from './delete_curation_button'; import { PromotedDocuments, OrganicDocuments } from './documents'; describe('AutomatedCuration', () => { @@ -33,6 +34,8 @@ describe('AutomatedCuration', () => { queries: ['query A', 'query B'], isFlyoutOpen: false, curation: { + promoted: [], + hidden: [], suggestion: { status: 'applied', }, @@ -89,13 +92,29 @@ describe('AutomatedCuration', () => { expect(pageTitle.find(EuiBadge)).toHaveLength(1); }); + it('displays a spinner in the title when loading', () => { + setMockValues({ ...values, dataLoading: true }); + + const wrapper = shallow(); + const pageTitle = shallow(
{getPageTitle(wrapper)}
); + + expect(pageTitle.find(EuiLoadingSpinner)).toHaveLength(1); + }); + + it('contains a button to delete the curation', () => { + const wrapper = shallow(); + const pageHeaderActions = getPageHeaderActions(wrapper); + + expect(pageHeaderActions.find(DeleteCurationButton)).toHaveLength(1); + }); + describe('convert to manual button', () => { let convertToManualButton: ShallowWrapper; let confirmSpy: jest.SpyInstance; beforeAll(() => { const wrapper = shallow(); - convertToManualButton = getPageHeaderActions(wrapper).childAt(0); + convertToManualButton = getPageHeaderActions(wrapper).find(EuiButton); confirmSpy = jest.spyOn(window, 'confirm'); }); @@ -107,12 +126,14 @@ describe('AutomatedCuration', () => { it('converts the curation upon user confirmation', () => { confirmSpy.mockReturnValueOnce(true); convertToManualButton.simulate('click'); + expect(actions.convertToManual).toHaveBeenCalled(); }); it('does not convert the curation if the user cancels', () => { confirmSpy.mockReturnValueOnce(false); convertToManualButton.simulate('click'); + expect(actions.convertToManual).not.toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.tsx index e5c212d8f292d2..fa34fa071b8552 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.tsx @@ -10,7 +10,7 @@ import { useParams } from 'react-router-dom'; import { useValues, useActions } from 'kea'; -import { EuiSpacer, EuiButton, EuiBadge } from '@elastic/eui'; +import { EuiButton, EuiBadge, EuiLoadingSpinner, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { AppSearchPageTemplate } from '../../layout'; import { AutomatedIcon } from '../components/automated_icon'; @@ -24,22 +24,25 @@ import { getCurationsBreadcrumbs } from '../utils'; import { HIDDEN_DOCUMENTS_TITLE, PROMOTED_DOCUMENTS_TITLE } from './constants'; import { CurationLogic } from './curation_logic'; +import { DeleteCurationButton } from './delete_curation_button'; import { PromotedDocuments, OrganicDocuments } from './documents'; export const AutomatedCuration: React.FC = () => { const { curationId } = useParams<{ curationId: string }>(); const logic = CurationLogic({ curationId }); const { convertToManual } = useActions(logic); - const { activeQuery, dataLoading, queries } = useValues(logic); + const { activeQuery, dataLoading, queries, curation } = useValues(logic); // This tab group is meant to visually mirror the dynamic group of tags in the ManualCuration component const pageTabs = [ { label: PROMOTED_DOCUMENTS_TITLE, + append: {curation.promoted.length}, isSelected: true, }, { label: HIDDEN_DOCUMENTS_TITLE, + append: 0, isSelected: false, disabled: true, }, @@ -51,30 +54,36 @@ export const AutomatedCuration: React.FC = () => { pageHeader={{ pageTitle: ( <> - {activeQuery}{' '} + {dataLoading ? : activeQuery}{' '} {AUTOMATED_LABEL} ), rightSideItems: [ - { - if (window.confirm(CONVERT_TO_MANUAL_CONFIRMATION)) convertToManual(); - }} - > - {COVERT_TO_MANUAL_BUTTON_LABEL} - , + + + + + + { + if (window.confirm(CONVERT_TO_MANUAL_CONFIRMATION)) convertToManual(); + }} + > + {COVERT_TO_MANUAL_BUTTON_LABEL} + + + , ], tabs: pageTabs, }} isLoading={dataLoading} > - ); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/constants.ts index 3ea907bfa3cbe2..b5e5108e42e771 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/constants.ts @@ -9,10 +9,10 @@ import { i18n } from '@kbn/i18n'; export const PROMOTED_DOCUMENTS_TITLE = i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.promotedDocuments.title', - { defaultMessage: 'Promoted documents' } + { defaultMessage: 'Promoted results' } ); export const HIDDEN_DOCUMENTS_TITLE = i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.title', - { defaultMessage: 'Hidden documents' } + { defaultMessage: 'Hidden results' } ); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts index d80a07e7569277..5c3ac6d700de4f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts @@ -21,7 +21,7 @@ describe('CurationLogic', () => { const { mount } = new LogicMounter(CurationLogic); const { http } = mockHttpValues; const { navigateToUrl } = mockKibanaValues; - const { clearFlashMessages, flashAPIErrors } = mockFlashMessageHelpers; + const { clearFlashMessages, flashAPIErrors, flashSuccessToast } = mockFlashMessageHelpers; const MOCK_CURATION_RESPONSE = { id: 'cur-123456789', @@ -249,23 +249,6 @@ describe('CurationLogic', () => { }); }); - describe('resetCuration', () => { - it('should clear promotedIds & hiddenIds & set dataLoading to true', () => { - mount({ promotedIds: ['hello'], hiddenIds: ['world'] }); - - CurationLogic.actions.resetCuration(); - - expect(CurationLogic.values).toEqual({ - ...DEFAULT_VALUES, - dataLoading: true, - promotedIds: [], - promotedDocumentsLoading: true, - hiddenIds: [], - hiddenDocumentsLoading: true, - }); - }); - }); - describe('onSelectPageTab', () => { it('should set the selected page tab', () => { mount({ @@ -336,6 +319,33 @@ describe('CurationLogic', () => { }); }); + describe('deleteCuration', () => { + it('should make an API call and navigate to the curations page', async () => { + http.delete.mockReturnValueOnce(Promise.resolve()); + mount({}, { curationId: 'cur-123456789' }); + jest.spyOn(CurationLogic.actions, 'onCurationLoad'); + + CurationLogic.actions.deleteCuration(); + await nextTick(); + + expect(http.delete).toHaveBeenCalledWith( + '/internal/app_search/engines/some-engine/curations/cur-123456789' + ); + expect(flashSuccessToast).toHaveBeenCalled(); + expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations'); + }); + + it('flashes any errors', async () => { + http.delete.mockReturnValueOnce(Promise.reject('error')); + mount({}, { curationId: 'cur-404' }); + + CurationLogic.actions.deleteCuration(); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalledWith('error'); + }); + }); + describe('loadCuration', () => { it('should set dataLoading state', () => { mount({ dataLoading: false }, { curationId: 'cur-123456789' }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.ts index c54a2d1f31e1d6..7b617dd89e962c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.ts @@ -7,11 +7,16 @@ import { kea, MakeLogicType } from 'kea'; -import { clearFlashMessages, flashAPIErrors } from '../../../../shared/flash_messages'; +import { + clearFlashMessages, + flashAPIErrors, + flashSuccessToast, +} from '../../../../shared/flash_messages'; import { HttpLogic } from '../../../../shared/http'; import { KibanaLogic } from '../../../../shared/kibana'; import { ENGINE_CURATIONS_PATH } from '../../../routes'; import { EngineLogic, generateEnginePath } from '../../engine'; +import { DELETE_SUCCESS_MESSAGE } from '../constants'; import { Curation } from '../types'; import { addDocument, removeDocument } from '../utils'; @@ -35,6 +40,7 @@ interface CurationValues { interface CurationActions { convertToManual(): void; + deleteCuration(): void; loadCuration(): void; onCurationLoad(curation: Curation): { curation: Curation }; updateCuration(): void; @@ -48,7 +54,6 @@ interface CurationActions { addHiddenId(id: string): { id: string }; removeHiddenId(id: string): { id: string }; clearHiddenIds(): void; - resetCuration(): void; onSelectPageTab(pageTab: CurationPageTabs): { pageTab: CurationPageTabs }; } @@ -60,6 +65,7 @@ export const CurationLogic = kea ({ convertToManual: true, + deleteCuration: true, loadCuration: true, onCurationLoad: (curation) => ({ curation }), updateCuration: true, @@ -73,7 +79,6 @@ export const CurationLogic = kea ({ id }), removeHiddenId: (id) => ({ id }), clearHiddenIds: true, - resetCuration: true, onSelectPageTab: (pageTab) => ({ pageTab }), }), reducers: () => ({ @@ -81,7 +86,6 @@ export const CurationLogic = kea true, - resetCuration: () => true, onCurationLoad: () => false, onCurationError: () => false, }, @@ -204,6 +208,21 @@ export const CurationLogic = kea { + const { http } = HttpLogic.values; + const { engineName } = EngineLogic.values; + const { navigateToUrl } = KibanaLogic.values; + + try { + await http.delete( + `/internal/app_search/engines/${engineName}/curations/${props.curationId}` + ); + navigateToUrl(generateEnginePath(ENGINE_CURATIONS_PATH)); + flashSuccessToast(DELETE_SUCCESS_MESSAGE); + } catch (e) { + flashAPIErrors(e); + } + }, loadCuration: async () => { const { http } = HttpLogic.values; const { engineName } = EngineLogic.values; @@ -260,9 +279,5 @@ export const CurationLogic = kea actions.updateCuration(), removeHiddenId: () => actions.updateCuration(), clearHiddenIds: () => actions.updateCuration(), - resetCuration: () => { - actions.clearPromotedIds(); - actions.clearHiddenIds(); - }, }), }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/delete_curation_button.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/delete_curation_button.test.tsx new file mode 100644 index 00000000000000..2a69b2bcd97488 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/delete_curation_button.test.tsx @@ -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 '../../../../__mocks__/shallow_useeffect.mock'; +import { setMockActions } from '../../../../__mocks__/kea_logic'; +import { mockUseParams } from '../../../../__mocks__/react_router'; +import '../../../__mocks__/engine_logic.mock'; + +import React from 'react'; + +import { shallow, ShallowWrapper } from 'enzyme'; + +import { EuiButton } from '@elastic/eui'; + +jest.mock('./curation_logic', () => ({ CurationLogic: jest.fn() })); + +import { DeleteCurationButton } from './delete_curation_button'; + +describe('DeleteCurationButton', () => { + const actions = { + deleteCuration: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + setMockActions(actions); + mockUseParams.mockReturnValueOnce({ curationId: 'hello-world' }); + }); + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.is(EuiButton)).toBe(true); + }); + + describe('restore defaults button', () => { + let wrapper: ShallowWrapper; + let confirmSpy: jest.SpyInstance; + + beforeAll(() => { + wrapper = shallow(); + confirmSpy = jest.spyOn(window, 'confirm'); + }); + + afterAll(() => { + confirmSpy.mockRestore(); + }); + + it('resets the curation upon user confirmation', () => { + confirmSpy.mockReturnValueOnce(true); + wrapper.simulate('click'); + expect(actions.deleteCuration).toHaveBeenCalled(); + }); + + it('does not reset the curation if the user cancels', () => { + confirmSpy.mockReturnValueOnce(false); + wrapper.simulate('click'); + expect(actions.deleteCuration).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/delete_curation_button.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/delete_curation_button.tsx new file mode 100644 index 00000000000000..49e1dc8b70b196 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/delete_curation_button.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { useParams } from 'react-router-dom'; + +import { useActions } from 'kea'; + +import { EuiButton } from '@elastic/eui'; + +import { DELETE_BUTTON_LABEL } from '../../../../shared/constants'; +import { DELETE_CONFIRMATION_MESSAGE } from '../constants'; + +import { CurationLogic } from '.'; + +export const DeleteCurationButton: React.FC = () => { + const { curationId } = useParams() as { curationId: string }; + const { deleteCuration } = useActions(CurationLogic({ curationId })); + + return ( + { + if (window.confirm(DELETE_CONFIRMATION_MESSAGE)) deleteCuration(); + }} + > + {DELETE_BUTTON_LABEL} + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.test.tsx index c2377d0109494e..7160931bcf402b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.test.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { EuiEmptyPrompt, EuiButtonEmpty } from '@elastic/eui'; +import { EuiEmptyPrompt, EuiButtonEmpty, EuiBadge } from '@elastic/eui'; import { DataPanel } from '../../../data_panel'; import { CurationResult } from '../results'; @@ -48,6 +48,14 @@ describe('HiddenDocuments', () => { expect(wrapper.find(CurationResult)).toHaveLength(5); }); + it('displays the number of documents in a badge', () => { + const wrapper = shallow(); + const Icon = wrapper.prop('iconType'); + const iconWrapper = shallow(); + + expect(iconWrapper.find(EuiBadge).prop('children')).toEqual(5); + }); + it('renders an empty state & hides the panel actions when empty', () => { setMockValues({ ...values, curation: { hidden: [] } }); const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.tsx index be50b03960acef..519808940fa1b0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { useValues, useActions } from 'kea'; -import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiEmptyPrompt } from '@elastic/eui'; +import { EuiBadge, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { DataPanel } from '../../../data_panel'; @@ -26,39 +26,37 @@ export const HiddenDocuments: React.FC = () => { const documents = curation.hidden; const hasDocuments = documents.length > 0; + const CountBadge: React.FC = () => {documents.length}; + return ( {HIDDEN_DOCUMENTS_TITLE}} - subtitle={i18n.translate( - 'xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.description', - { defaultMessage: 'Hidden documents will not appear in organic results.' } - )} action={ hasDocuments && ( - - - - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.removeAllButtonLabel', - { defaultMessage: 'Restore all' } + { defaultMessage: 'Unhide all' } )} + + + ) } isLoading={hiddenDocumentsLoading} > {hasDocuments ? ( - documents.map((document) => ( + documents.map((document, index) => ( { expect(titleText).toEqual('Top organic documents for "world"'); }); - it('shows a title when the curation is manual', () => { - setMockValues({ ...values, isAutomated: false }); - const wrapper = shallow(); - - expect(wrapper.find(DataPanel).prop('subtitle')).toContain('Promote results'); - }); - it('renders a loading state', () => { setMockValues({ ...values, organicDocumentsLoading: true }); const wrapper = shallow(); @@ -74,13 +67,20 @@ describe('OrganicDocuments', () => { }); describe('empty state', () => { - it('renders', () => { + it('renders when organic results is empty', () => { setMockValues({ ...values, curation: { organic: [] } }); const wrapper = shallow(); expect(wrapper.find(EuiEmptyPrompt)).toHaveLength(1); }); + it('renders when organic results is undefined', () => { + setMockValues({ ...values, curation: { organic: undefined } }); + const wrapper = shallow(); + + expect(wrapper.find(EuiEmptyPrompt)).toHaveLength(1); + }); + it('tells the user to modify the query if the curation is manual', () => { setMockValues({ ...values, curation: { organic: [] }, isAutomated: false }); const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/organic_documents.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/organic_documents.tsx index 7314376a4a7abd..166cce9029489b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/organic_documents.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/organic_documents.tsx @@ -13,14 +13,12 @@ import { EuiLoadingContent, EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import { LeafIcon } from '../../../../../shared/icons'; + import { DataPanel } from '../../../data_panel'; import { Result } from '../../../result/types'; -import { - RESULT_ACTIONS_DIRECTIONS, - PROMOTE_DOCUMENT_ACTION, - HIDE_DOCUMENT_ACTION, -} from '../../constants'; +import { PROMOTE_DOCUMENT_ACTION, HIDE_DOCUMENT_ACTION } from '../../constants'; import { CurationLogic } from '../curation_logic'; import { CurationResult } from '../results'; @@ -28,14 +26,13 @@ export const OrganicDocuments: React.FC = () => { const { addPromotedId, addHiddenId } = useActions(CurationLogic); const { curation, activeQuery, isAutomated, organicDocumentsLoading } = useValues(CurationLogic); - const documents = curation.organic; + const documents = curation.organic || []; const hasDocuments = documents.length > 0 && !organicDocumentsLoading; const currentQuery = activeQuery; return ( {i18n.translate( @@ -47,12 +44,12 @@ export const OrganicDocuments: React.FC = () => { )} } - subtitle={!isAutomated && RESULT_ACTIONS_DIRECTIONS} > {hasDocuments ? ( - documents.map((document: Result) => ( + documents.map((document: Result, index) => ( { return draggableWrapper.renderProp('children')({}, {}, {}); }; + it('displays the number of documents in a badge', () => { + const wrapper = shallow(); + const Icon = wrapper.prop('iconType'); + const iconWrapper = shallow(); + + expect(iconWrapper.find(EuiBadge).prop('children')).toEqual(4); + }); + it('renders a list of draggable promoted documents', () => { const wrapper = shallow(); @@ -57,22 +72,6 @@ describe('PromotedDocuments', () => { }); }); - it('informs the user documents can be re-ordered if the curation is manual', () => { - setMockValues({ ...values, isAutomated: false }); - const wrapper = shallow(); - const subtitle = mountWithIntl(wrapper.prop('subtitle')); - - expect(subtitle.text()).toContain('Documents can be re-ordered'); - }); - - it('informs the user the curation is managed if the curation is automated', () => { - setMockValues({ ...values, isAutomated: true }); - const wrapper = shallow(); - const subtitle = mountWithIntl(wrapper.prop('subtitle')); - - expect(subtitle.text()).toContain('managed by App Search'); - }); - describe('empty state', () => { it('renders', () => { setMockValues({ ...values, curation: { promoted: [] } }); @@ -90,18 +89,12 @@ describe('PromotedDocuments', () => { }); }); - it('hides the panel actions when empty', () => { - setMockValues({ ...values, curation: { promoted: [] } }); - const wrapper = shallow(); - - expect(wrapper.find(DataPanel).prop('action')).toBe(false); - }); - - it('hides the panel actions when the curation is automated', () => { + it('shows a message when the curation is automated', () => { setMockValues({ ...values, isAutomated: true }); const wrapper = shallow(); + const panelAction = shallow(wrapper.find(DataPanel).prop('action') as React.ReactElement); - expect(wrapper.find(DataPanel).prop('action')).toBe(false); + expect(panelAction.find(EuiTextColor)).toHaveLength(1); }); it('renders a loading state', () => { @@ -136,6 +129,13 @@ describe('PromotedDocuments', () => { expect(actions.clearPromotedIds).toHaveBeenCalled(); }); + it('hides the demote all button when there are on promoted results', () => { + setMockValues({ ...values, curation: { promoted: [] } }); + const wrapper = shallow(); + + expect(wrapper.find(DataPanel).prop('action')).toEqual(false); + }); + describe('dragging', () => { it('calls setPromotedIds with the reordered list when users are done dragging', () => { const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/promoted_documents.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/promoted_documents.tsx index 377e9d5d9a56cf..c953fb210c03d6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/promoted_documents.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/promoted_documents.tsx @@ -19,9 +19,10 @@ import { EuiDroppable, EuiDraggable, euiDragDropReorder, + EuiBadge, + EuiText, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; import { DataPanel } from '../../../data_panel'; @@ -43,45 +44,45 @@ export const PromotedDocuments: React.FC = () => { } }; + const CountBadge: React.FC = () => {documents.length}; + return ( {PROMOTED_DOCUMENTS_TITLE}} - subtitle={ - isAutomated ? ( - - ) : ( - - ) - } action={ - !isAutomated && - hasDocuments && ( - - - - - - + isAutomated ? ( + +

+ {i18n.translate( - 'xpack.enterpriseSearch.appSearch.engine.curations.promotedDocuments.removeAllButtonLabel', - { defaultMessage: 'Demote all' } + 'xpack.enterpriseSearch.appSearch.engine.curations.promotedDocuments.managedByAppSearchDescription', + { defaultMessage: 'This curation is being automated by App Search' } )} - - - + +

+
+ ) : ( + hasDocuments && ( + + + + {i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.promotedDocuments.removeAllButtonLabel', + { defaultMessage: 'Demote all' } + )} + + + + + + + ) ) } isLoading={promotedDocumentsLoading} @@ -89,9 +90,9 @@ export const PromotedDocuments: React.FC = () => { {hasDocuments ? ( - {documents.map((document, i: number) => ( + {documents.map((document, index) => ( { {(provided) => ( ({ CurationLogic: jest.fn() })); import { CurationLogic } from './curation_logic'; +import { DeleteCurationButton } from './delete_curation_button'; import { PromotedDocuments, HiddenDocuments } from './documents'; import { ManualCuration } from './manual_curation'; +import { ActiveQuerySelect, ManageQueriesModal } from './queries'; import { AddResultFlyout } from './results'; import { SuggestedDocumentsCallout } from './suggested_documents_callout'; @@ -32,9 +34,13 @@ describe('ManualCuration', () => { queries: ['query A', 'query B'], isFlyoutOpen: false, selectedPageTab: 'promoted', + curation: { + promoted: [], + hidden: [], + }, }; const actions = { - resetCuration: jest.fn(), + deleteCuration: jest.fn(), onSelectPageTab: jest.fn(), }; @@ -108,31 +114,26 @@ describe('ManualCuration', () => { expect(CurationLogic).toHaveBeenCalledWith({ curationId: 'hello-world' }); }); - describe('restore defaults button', () => { - let restoreDefaultsButton: ShallowWrapper; - let confirmSpy: jest.SpyInstance; + describe('page header actions', () => { + let pageHeaderActions: ShallowWrapper; beforeAll(() => { const wrapper = shallow(); - restoreDefaultsButton = getPageHeaderActions(wrapper).childAt(0); - - confirmSpy = jest.spyOn(window, 'confirm'); + pageHeaderActions = getPageHeaderActions(wrapper); }); - afterAll(() => { - confirmSpy.mockRestore(); + it('contains a button to manage queries and an active query selector', () => { + expect(pageHeaderActions.find(ManageQueriesModal)).toHaveLength(1); }); - it('resets the curation upon user confirmation', () => { - confirmSpy.mockReturnValueOnce(true); - restoreDefaultsButton.simulate('click'); - expect(actions.resetCuration).toHaveBeenCalled(); + it('contains a button to delete the curation', () => { + expect(pageHeaderActions.find(DeleteCurationButton)).toHaveLength(1); }); + }); - it('does not reset the curation if the user cancels', () => { - confirmSpy.mockReturnValueOnce(false); - restoreDefaultsButton.simulate('click'); - expect(actions.resetCuration).not.toHaveBeenCalled(); - }); + it('contains an active query selector', () => { + const wrapper = shallow(); + + expect(wrapper.find(ActiveQuerySelect)).toHaveLength(1); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/manual_curation.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/manual_curation.tsx index ab031ca4a5ee78..3aee306e3d2ff2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/manual_curation.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/manual_curation.tsx @@ -10,15 +10,15 @@ import { useParams } from 'react-router-dom'; import { useValues, useActions } from 'kea'; -import { EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui'; +import { EuiBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { RESTORE_DEFAULTS_BUTTON_LABEL } from '../../../constants'; import { AppSearchPageTemplate } from '../../layout'; -import { MANAGE_CURATION_TITLE, RESTORE_CONFIRMATION } from '../constants'; +import { MANAGE_CURATION_TITLE } from '../constants'; import { getCurationsBreadcrumbs } from '../utils'; import { PROMOTED_DOCUMENTS_TITLE, HIDDEN_DOCUMENTS_TITLE } from './constants'; import { CurationLogic } from './curation_logic'; +import { DeleteCurationButton } from './delete_curation_button'; import { PromotedDocuments, OrganicDocuments, HiddenDocuments } from './documents'; import { ActiveQuerySelect, ManageQueriesModal } from './queries'; import { AddResultLogic, AddResultFlyout } from './results'; @@ -26,18 +26,22 @@ import { SuggestedDocumentsCallout } from './suggested_documents_callout'; export const ManualCuration: React.FC = () => { const { curationId } = useParams() as { curationId: string }; - const { onSelectPageTab, resetCuration } = useActions(CurationLogic({ curationId })); - const { dataLoading, queries, selectedPageTab } = useValues(CurationLogic({ curationId })); + const { onSelectPageTab } = useActions(CurationLogic({ curationId })); + const { dataLoading, queries, selectedPageTab, curation } = useValues( + CurationLogic({ curationId }) + ); const { isFlyoutOpen } = useValues(AddResultLogic); const pageTabs = [ { label: PROMOTED_DOCUMENTS_TITLE, + append: {curation.promoted.length}, isSelected: selectedPageTab === 'promoted', onClick: () => onSelectPageTab('promoted'), }, { label: HIDDEN_DOCUMENTS_TITLE, + append: {curation.hidden.length}, isSelected: selectedPageTab === 'hidden', onClick: () => onSelectPageTab('hidden'), }, @@ -49,32 +53,23 @@ export const ManualCuration: React.FC = () => { pageHeader={{ pageTitle: MANAGE_CURATION_TITLE, rightSideItems: [ - { - if (window.confirm(RESTORE_CONFIRMATION)) resetCuration(); - }} - > - {RESTORE_DEFAULTS_BUTTON_LABEL} - , + + + + + + + + , ], tabs: pageTabs, }} isLoading={dataLoading} > - - - - - - - - - - + + {selectedPageTab === 'promoted' && } {selectedPageTab === 'promoted' && } {selectedPageTab === 'hidden' && } - {isFlyoutOpen && } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/queries/active_query_select.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/queries/active_query_select.tsx index d4f42a8d70ad35..4e62e3fb7ec7aa 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/queries/active_query_select.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/queries/active_query_select.tsx @@ -23,6 +23,12 @@ export const ActiveQuerySelect: React.FC = () => { label={i18n.translate('xpack.enterpriseSearch.appSearch.engine.curations.activeQueryLabel', { defaultMessage: 'Active query', })} + helpText={i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.activeQueryHelpText', + { + defaultMessage: 'Select a query to view the organic search results for them', + } + )} fullWidth > { return ( <> - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.manageQueryButtonLabel', { defaultMessage: 'Manage queries' } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/add_result_button.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/add_result_button.tsx index f2285064da3074..956b0ba0645c2d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/add_result_button.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/add_result_button.tsx @@ -21,7 +21,7 @@ export const AddResultButton: React.FC = () => { const { isAutomated } = useValues(CurationLogic); return ( - + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.curations.addResult.buttonLabel', { defaultMessage: 'Add result manually', })} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.test.tsx index 67a26f2ecd4b6d..36a2f47956c217 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.test.tsx @@ -51,4 +51,16 @@ describe('CurationResult', () => { expect(wrapper.find(Result).prop('actions')).toEqual(mockActions); expect(wrapper.find(Result).prop('dragHandleProps')).toEqual(mockDragging); }); + + it('increments the result index before passing it on', () => { + wrapper = shallow( + + ); + expect(wrapper.find(Result).prop('resultPosition')).toEqual(6); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.tsx index c737d93ce18238..f0086e771234b0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.tsx @@ -17,12 +17,13 @@ import { Result } from '../../../result'; import { Result as ResultType, ResultAction } from '../../../result/types'; interface Props { - result: ResultType; actions: ResultAction[]; dragHandleProps?: DraggableProvidedDragHandleProps; + result: ResultType; + index?: number; } -export const CurationResult: React.FC = ({ result, actions, dragHandleProps }) => { +export const CurationResult: React.FC = ({ actions, dragHandleProps, result, index }) => { const { isMetaEngine, engine: { schema }, @@ -36,6 +37,7 @@ export const CurationResult: React.FC = ({ result, actions, dragHandlePro isMetaEngine={isMetaEngine} schemaForTypeHighlights={schema} dragHandleProps={dragHandleProps} + resultPosition={typeof index === 'undefined' ? undefined : index + 1} /> diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.ts index 76adfa4b6ed4dd..e623379e58d3f8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.ts @@ -20,7 +20,7 @@ import { updateMetaPageIndex } from '../../../shared/table_pagination'; import { ENGINE_CURATION_PATH } from '../../routes'; import { EngineLogic, generateEnginePath } from '../engine'; -import { DELETE_MESSAGE, SUCCESS_MESSAGE } from './constants'; +import { DELETE_CONFIRMATION_MESSAGE, DELETE_SUCCESS_MESSAGE } from './constants'; import { Curation, CurationsAPIResponse } from './types'; type CurationsPageTabs = 'overview' | 'settings'; @@ -102,11 +102,11 @@ export const CurationsLogic = kea { - const handleAcceptClick = jest.fn(); - const handleRejectClick = jest.fn(); + const actions = { + acceptSuggestion: jest.fn(), + rejectSuggestion: jest.fn(), + }; + + beforeAll(() => { + setMockActions(actions); + }); it('renders', () => { - const wrapper = shallow( - - ); + const wrapper = shallow(); wrapper.find('[data-test-subj="rejectButton"]').simulate('click'); - expect(handleRejectClick).toHaveBeenCalled(); + expect(actions.rejectSuggestion).toHaveBeenCalled(); wrapper.find('[data-test-subj="acceptButton"]').simulate('click'); - expect(handleAcceptClick).toHaveBeenCalled(); + expect(actions.acceptSuggestion).toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_action_bar.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_action_bar.tsx index 42f4cbbb7d7a94..536d30637549ed 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_action_bar.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_action_bar.tsx @@ -7,17 +7,17 @@ import React from 'react'; +import { useActions } from 'kea'; + import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiPanel, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { CurationActionsPopover } from './curation_actions_popover'; +import { CurationSuggestionLogic } from './curation_suggestion_logic'; -interface Props { - onAcceptClick: (event: React.MouseEvent) => void; - onRejectClick: (event: React.MouseEvent) => void; -} +export const CurationActionBar: React.FC = () => { + const { acceptSuggestion, rejectSuggestion } = useActions(CurationSuggestionLogic); -export const CurationActionBar: React.FC = ({ onAcceptClick, onRejectClick }) => { return ( @@ -41,7 +41,7 @@ export const CurationActionBar: React.FC = ({ onAcceptClick, onRejectClic color="danger" iconType="crossInACircleFilled" data-test-subj="rejectButton" - onClick={onRejectClick} + onClick={rejectSuggestion} > {i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.rejectButtonLabel', @@ -55,7 +55,7 @@ export const CurationActionBar: React.FC = ({ onAcceptClick, onRejectClic color="success" iconType="checkInCircleFilled" data-test-subj="acceptButton" - onClick={onAcceptClick} + onClick={acceptSuggestion} > {i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.acceptButtonLabel', @@ -64,12 +64,7 @@ export const CurationActionBar: React.FC = ({ onAcceptClick, onRejectClic
- {}} - onAutomate={() => {}} - onReject={() => {}} - onTurnOff={() => {}} - /> +
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_actions_popover.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_actions_popover.test.tsx index 33d00ca2b78990..c5caff68bc0fab 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_actions_popover.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_actions_popover.test.tsx @@ -5,6 +5,8 @@ * 2.0. */ +import { setMockActions } from '../../../../../__mocks__/kea_logic'; + import React from 'react'; import { shallow } from 'enzyme'; @@ -12,48 +14,40 @@ import { shallow } from 'enzyme'; import { CurationActionsPopover } from './curation_actions_popover'; describe('CurationActionsPopover', () => { - const handleAccept = jest.fn(); - const handleAutomate = jest.fn(); - const handleReject = jest.fn(); - const handleTurnOff = jest.fn(); + const actions = { + acceptSuggestion: jest.fn(), + acceptAndAutomateSuggestion: jest.fn(), + rejectSuggestion: jest.fn(), + rejectAndDisableSuggestion: jest.fn(), + }; + + beforeAll(() => { + setMockActions(actions); + }); beforeEach(() => { jest.clearAllMocks(); }); it('renders', () => { - const wrapper = shallow( - - ); + const wrapper = shallow(); expect(wrapper.isEmptyRender()).toBe(false); wrapper.find('[data-test-subj="acceptButton"]').simulate('click'); - expect(handleAccept).toHaveBeenCalled(); + expect(actions.acceptSuggestion).toHaveBeenCalled(); wrapper.find('[data-test-subj="automateButton"]').simulate('click'); - expect(handleAutomate).toHaveBeenCalled(); + expect(actions.acceptAndAutomateSuggestion).toHaveBeenCalled(); wrapper.find('[data-test-subj="rejectButton"]').simulate('click'); - expect(handleReject).toHaveBeenCalled(); + expect(actions.rejectSuggestion).toHaveBeenCalled(); wrapper.find('[data-test-subj="turnoffButton"]').simulate('click'); - expect(handleTurnOff).toHaveBeenCalled(); + expect(actions.rejectAndDisableSuggestion).toHaveBeenCalled(); }); it('can open and close', () => { - const wrapper = shallow( - - ); + const wrapper = shallow(); expect(wrapper.prop('isOpen')).toBe(false); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_actions_popover.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_actions_popover.tsx index ef7b42fb705f12..0ae923830cd782 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_actions_popover.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_actions_popover.tsx @@ -7,6 +7,8 @@ import React, { useState } from 'react'; +import { useActions } from 'kea'; + import { EuiButtonIcon, EuiListGroup, @@ -16,20 +18,16 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -interface Props { - onAccept: () => void; - onAutomate: () => void; - onReject: () => void; - onTurnOff: () => void; -} +import { CurationSuggestionLogic } from './curation_suggestion_logic'; -export const CurationActionsPopover: React.FC = ({ - onAccept, - onAutomate, - onReject, - onTurnOff, -}) => { +export const CurationActionsPopover: React.FC = () => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const { + acceptSuggestion, + acceptAndAutomateSuggestion, + rejectSuggestion, + rejectAndDisableSuggestion, + } = useActions(CurationSuggestionLogic); const onButtonClick = () => setIsPopoverOpen(!isPopoverOpen); const closePopover = () => setIsPopoverOpen(false); @@ -63,7 +61,7 @@ export const CurationActionsPopover: React.FC = ({ 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.actionsAcceptButtonLabel', { defaultMessage: 'Accept this suggestion' } )} - onClick={onAccept} + onClick={acceptSuggestion} data-test-subj="acceptButton" /> = ({ 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.actionsAutomateButtonLabel', { defaultMessage: 'Automate - always accept new suggestions for this query' } )} - onClick={onAutomate} + onClick={acceptAndAutomateSuggestion} data-test-subj="automateButton" /> = ({ 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.actionsRejectButtonLabel', { defaultMessage: 'Reject this suggestion' } )} - onClick={onReject} + onClick={rejectSuggestion} data-test-subj="rejectButton" /> = ({ 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.actionsTurnOffButtonLabel', { defaultMessage: 'Reject and turn off suggestions for this query' } )} - onClick={onTurnOff} + onClick={rejectAndDisableSuggestion} data-test-subj="turnoffButton" /> diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_result_panel.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_result_panel.test.tsx index 80d5a874c81025..77324566e5a1d8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_result_panel.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_result_panel.test.tsx @@ -48,6 +48,7 @@ describe('CurationResultPanel', () => { expect(wrapper.find(Result).length).toBe(2); expect(wrapper.find(Result).at(0).props()).toEqual({ result: results[0], + resultPosition: 1, isMetaEngine: true, schemaForTypeHighlights: values.engine.schema, }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_result_panel.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_result_panel.tsx index 5a21bfcb38843f..bbd61804ad3410 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_result_panel.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_result_panel.tsx @@ -72,12 +72,13 @@ export const CurationResultPanel: React.FC = ({ variant, results }) => { className={`curationResultPanel curationResultPanel--${variant}`} > {results.length > 0 ? ( - results.map((result) => ( + results.map((result, index) => ( )) diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion.tsx index 3191d4e912cff5..8e1e6487197f9f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion.tsx @@ -65,10 +65,7 @@ export const CurationSuggestion: React.FC = () => { pageTitle: suggestionQuery, }} > - alert('Accepted')} - onRejectClick={() => alert('Rejected')} - /> + @@ -129,12 +126,13 @@ export const CurationSuggestion: React.FC = () => { gutterSize="s" data-test-subj="currentOrganicResults" > - {currentOrganicResults.map((result: ResultType) => ( + {currentOrganicResults.map((result: ResultType, index) => ( ))} @@ -148,12 +146,13 @@ export const CurationSuggestion: React.FC = () => { gutterSize="s" data-test-subj="proposedOrganicResults" > - {proposedOrganicResults.map((result: ResultType) => ( + {proposedOrganicResults.map((result: ResultType, index) => ( ))} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts index af694c3756fd1c..2ace55133d6fdd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts @@ -9,6 +9,7 @@ import { LogicMounter, mockFlashMessageHelpers, mockHttpValues, + mockKibanaValues, } from '../../../../../__mocks__/kea_logic'; import { set } from 'lodash/fp'; @@ -32,7 +33,8 @@ const suggestion: CurationSuggestion = { query: 'foo', updated_at: '2021-07-08T14:35:50Z', promoted: ['1', '2', '3'], - status: 'applied', + status: 'pending', + operation: 'create', }; const curation = { @@ -115,13 +117,51 @@ const MOCK_DOCUMENTS_RESPONSE = { describe('CurationSuggestionLogic', () => { const { mount } = new LogicMounter(CurationSuggestionLogic); - const { flashAPIErrors } = mockFlashMessageHelpers; + const { flashAPIErrors, setQueuedErrorMessage } = mockFlashMessageHelpers; + const { navigateToUrl } = mockKibanaValues; + const mountLogic = (props: object = {}) => { mount(props, { query: 'foo-query' }); }; const { http } = mockHttpValues; + const itHandlesInlineErrors = (callback: () => void) => { + it('handles inline errors', async () => { + http.put.mockReturnValueOnce( + Promise.resolve({ + results: [ + { + error: 'error', + }, + ], + }) + ); + mountLogic({ + suggestion, + }); + + callback(); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalledWith('error'); + }); + }; + + const itHandlesErrors = (httpMethod: any, callback: () => void) => { + it('handles errors', async () => { + httpMethod.mockReturnValueOnce(Promise.reject('error')); + mountLogic({ + suggestion, + }); + + callback(); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalledWith('error'); + }); + }; + beforeEach(() => { jest.clearAllMocks(); }); @@ -207,7 +247,8 @@ describe('CurationSuggestionLogic', () => { query: 'foo', updated_at: '2021-07-08T14:35:50Z', promoted: ['1', '2', '3'], - status: 'applied', + status: 'pending', + operation: 'create', }, // Note that these were re-ordered to match the 'promoted' list above, and since document // 3 was not found it is not included in this list @@ -243,9 +284,7 @@ describe('CurationSuggestionLogic', () => { ); http.post.mockReturnValueOnce(Promise.resolve(MOCK_DOCUMENTS_RESPONSE)); http.get.mockReturnValueOnce(Promise.resolve(curation)); - mountLogic({ - suggestion: set('curation_id', 'cur-6155e69c7a2f2e4f756303fd', suggestion), - }); + mountLogic(); jest.spyOn(CurationSuggestionLogic.actions, 'onSuggestionLoaded'); CurationSuggestionLogic.actions.loadSuggestion(); @@ -255,7 +294,6 @@ describe('CurationSuggestionLogic', () => { '/internal/app_search/engines/some-engine/curations/cur-6155e69c7a2f2e4f756303fd', { query: { skip_record_analytics: 'true' } } ); - await nextTick(); expect(CurationSuggestionLogic.actions.onSuggestionLoaded).toHaveBeenCalledWith({ suggestion: expect.any(Object), @@ -264,14 +302,204 @@ describe('CurationSuggestionLogic', () => { }); }); - it('handles errors', async () => { - http.post.mockReturnValueOnce(Promise.reject('error')); - mount(); + // This could happen if a user applies a suggestion and then navigates back to a detail page via + // the back button, etc. The suggestion still exists, it's just not in a "pending" state + // so we can show it.ga + it('will redirect if the suggestion is not found', async () => { + http.post.mockReturnValueOnce(Promise.resolve(set('results', [], MOCK_RESPONSE))); + mountLogic(); + CurationSuggestionLogic.actions.loadSuggestion(); + await nextTick(); + expect(setQueuedErrorMessage).toHaveBeenCalled(); + expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations'); + }); + itHandlesErrors(http.post, () => { CurationSuggestionLogic.actions.loadSuggestion(); + }); + }); + + describe('acceptSuggestion', () => { + it('will make an http call to apply the suggestion, and then navigate to that detail page', async () => { + http.put.mockReturnValueOnce( + Promise.resolve({ + results: [ + { + ...suggestion, + status: 'accepted', + curation_id: 'cur-6155e69c7a2f2e4f756303fd', + }, + ], + }) + ); + mountLogic({ + suggestion, + }); + + CurationSuggestionLogic.actions.acceptSuggestion(); + await nextTick(); + + expect(http.put).toHaveBeenCalledWith( + '/internal/app_search/engines/some-engine/search_relevance_suggestions', + { + body: JSON.stringify([ + { + query: 'foo', + type: 'curation', + status: 'applied', + }, + ]), + } + ); + + expect(navigateToUrl).toHaveBeenCalledWith( + '/engines/some-engine/curations/cur-6155e69c7a2f2e4f756303fd' + ); + }); + + itHandlesErrors(http.put, () => { + CurationSuggestionLogic.actions.acceptSuggestion(); + }); + + itHandlesInlineErrors(() => { + CurationSuggestionLogic.actions.acceptSuggestion(); + }); + }); + + describe('acceptAndAutomateSuggestion', () => { + it('will make an http call to apply the suggestion, and then navigate to that detail page', async () => { + http.put.mockReturnValueOnce( + Promise.resolve({ + results: [ + { + ...suggestion, + status: 'accepted', + curation_id: 'cur-6155e69c7a2f2e4f756303fd', + }, + ], + }) + ); + mountLogic({ + suggestion, + }); + + CurationSuggestionLogic.actions.acceptAndAutomateSuggestion(); + await nextTick(); + + expect(http.put).toHaveBeenCalledWith( + '/internal/app_search/engines/some-engine/search_relevance_suggestions', + { + body: JSON.stringify([ + { + query: 'foo', + type: 'curation', + status: 'automated', + }, + ]), + } + ); + + expect(navigateToUrl).toHaveBeenCalledWith( + '/engines/some-engine/curations/cur-6155e69c7a2f2e4f756303fd' + ); + }); + + itHandlesErrors(http.put, () => { + CurationSuggestionLogic.actions.acceptAndAutomateSuggestion(); + }); + + itHandlesInlineErrors(() => { + CurationSuggestionLogic.actions.acceptAndAutomateSuggestion(); + }); + }); + + describe('rejectSuggestion', () => { + it('will make an http call to apply the suggestion, and then navigate back the curations page', async () => { + http.put.mockReturnValueOnce( + Promise.resolve({ + results: [ + { + ...suggestion, + status: 'rejected', + curation_id: 'cur-6155e69c7a2f2e4f756303fd', + }, + ], + }) + ); + mountLogic({ + suggestion, + }); + + CurationSuggestionLogic.actions.rejectSuggestion(); + await nextTick(); + + expect(http.put).toHaveBeenCalledWith( + '/internal/app_search/engines/some-engine/search_relevance_suggestions', + { + body: JSON.stringify([ + { + query: 'foo', + type: 'curation', + status: 'rejected', + }, + ]), + } + ); + + expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations'); + }); + + itHandlesErrors(http.put, () => { + CurationSuggestionLogic.actions.rejectSuggestion(); + }); + + itHandlesInlineErrors(() => { + CurationSuggestionLogic.actions.rejectSuggestion(); + }); + }); + + describe('rejectAndDisableSuggestion', () => { + it('will make an http call to apply the suggestion, and then navigate back the curations page', async () => { + http.put.mockReturnValueOnce( + Promise.resolve({ + results: [ + { + ...suggestion, + status: 'disabled', + curation_id: 'cur-6155e69c7a2f2e4f756303fd', + }, + ], + }) + ); + mountLogic({ + suggestion, + }); + + CurationSuggestionLogic.actions.rejectAndDisableSuggestion(); await nextTick(); - expect(flashAPIErrors).toHaveBeenCalledWith('error'); + expect(http.put).toHaveBeenCalledWith( + '/internal/app_search/engines/some-engine/search_relevance_suggestions', + { + body: JSON.stringify([ + { + query: 'foo', + type: 'curation', + status: 'disabled', + }, + ]), + } + ); + + expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations'); + }); + + itHandlesErrors(http.put, () => { + CurationSuggestionLogic.actions.rejectAndDisableSuggestion(); + }); + + itHandlesInlineErrors(() => { + CurationSuggestionLogic.actions.rejectAndDisableSuggestion(); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.ts index 3c3af8bfd96c83..6749b510edeba3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.ts @@ -8,12 +8,23 @@ import { kea, MakeLogicType } from 'kea'; import { HttpSetup } from 'kibana/public'; -import { flashAPIErrors } from '../../../../../shared/flash_messages'; +import { i18n } from '@kbn/i18n'; + +import { + flashAPIErrors, + setQueuedErrorMessage, + setQueuedSuccessMessage, +} from '../../../../../shared/flash_messages'; import { HttpLogic } from '../../../../../shared/http'; -import { EngineLogic } from '../../../engine'; +import { KibanaLogic } from '../../../../../shared/kibana'; +import { ENGINE_CURATIONS_PATH, ENGINE_CURATION_PATH } from '../../../../routes'; +import { EngineLogic, generateEnginePath } from '../../../engine'; import { Result } from '../../../result/types'; import { Curation, CurationSuggestion } from '../../types'; +interface Error { + error: string; +} interface CurationSuggestionValues { dataLoading: boolean; suggestion: CurationSuggestion | null; @@ -36,6 +47,10 @@ interface CurationSuggestionActions { suggestedPromotedDocuments: Result[]; curation: Curation; }; + acceptSuggestion(): void; + acceptAndAutomateSuggestion(): void; + rejectSuggestion(): void; + rejectAndDisableSuggestion(): void; } interface CurationSuggestionProps { @@ -53,6 +68,10 @@ export const CurationSuggestionLogic = kea< suggestedPromotedDocuments, curation, }), + acceptSuggestion: true, + acceptAndAutomateSuggestion: true, + rejectSuggestion: true, + rejectAndDisableSuggestion: true, }), reducers: () => ({ dataLoading: [ @@ -81,13 +100,14 @@ export const CurationSuggestionLogic = kea< }, ], }), - listeners: ({ actions, props }) => ({ + listeners: ({ actions, values, props }) => ({ loadSuggestion: async () => { const { http } = HttpLogic.values; const { engineName } = EngineLogic.values; try { - const suggestion = await getSuggestions(http, engineName, props.query); + const suggestion = await getSuggestion(http, engineName, props.query); + if (!suggestion) return; const promotedIds: string[] = suggestion.promoted; const documentDetailsResopnse = getDocumentDetails(http, engineName, promotedIds); @@ -116,14 +136,144 @@ export const CurationSuggestionLogic = kea< flashAPIErrors(e); } }, + acceptSuggestion: async () => { + const { http } = HttpLogic.values; + const { engineName } = EngineLogic.values; + const { suggestion } = values; + + try { + const updatedSuggestion = await updateSuggestion( + http, + engineName, + suggestion!.query, + 'applied' + ); + + setQueuedSuccessMessage( + i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.successfullyAppliedMessage', + { defaultMessage: 'Suggestion was succefully applied.' } + ) + ); + KibanaLogic.values.navigateToUrl( + generateEnginePath(ENGINE_CURATION_PATH, { + curationId: updatedSuggestion.curation_id, + }) + ); + } catch (e) { + flashAPIErrors(e); + } + }, + acceptAndAutomateSuggestion: async () => { + const { http } = HttpLogic.values; + const { engineName } = EngineLogic.values; + const { suggestion } = values; + + try { + const updatedSuggestion = await updateSuggestion( + http, + engineName, + suggestion!.query, + 'automated' + ); + + setQueuedSuccessMessage( + i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.successfullyAutomatedMessage', + { + defaultMessage: + 'Suggestion was succefully applied and all future suggestions for the query "{query}" will be automatically applied.', + values: { query: suggestion!.query }, + } + ) + ); + KibanaLogic.values.navigateToUrl( + generateEnginePath(ENGINE_CURATION_PATH, { + curationId: updatedSuggestion.curation_id, + }) + ); + } catch (e) { + flashAPIErrors(e); + } + }, + rejectSuggestion: async () => { + const { http } = HttpLogic.values; + const { engineName } = EngineLogic.values; + const { suggestion } = values; + + try { + await updateSuggestion(http, engineName, suggestion!.query, 'rejected'); + + setQueuedSuccessMessage( + i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.successfullyRejectedMessage', + { + defaultMessage: 'Suggestion was succefully rejected.', + } + ) + ); + KibanaLogic.values.navigateToUrl(generateEnginePath(ENGINE_CURATIONS_PATH)); + } catch (e) { + flashAPIErrors(e); + } + }, + rejectAndDisableSuggestion: async () => { + const { http } = HttpLogic.values; + const { engineName } = EngineLogic.values; + const { suggestion } = values; + + try { + await updateSuggestion(http, engineName, suggestion!.query, 'disabled'); + + setQueuedSuccessMessage( + i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.successfullyDisabledMessage', + { + defaultMessage: + 'Suggestion was succefully rejected and you will no longer receive suggestions for the query "{query}".', + values: { query: suggestion!.query }, + } + ) + ); + KibanaLogic.values.navigateToUrl(generateEnginePath(ENGINE_CURATIONS_PATH)); + } catch (e) { + flashAPIErrors(e); + } + }, }), }); -const getSuggestions = async ( +const updateSuggestion = async ( + http: HttpSetup, + engineName: string, + query: string, + status: string +) => { + const response = await http.put<{ results: Array }>( + `/internal/app_search/engines/${engineName}/search_relevance_suggestions`, + { + body: JSON.stringify([ + { + query, + type: 'curation', + status, + }, + ]), + } + ); + + if (response.results[0].hasOwnProperty('error')) { + throw (response.results[0] as Error).error; + } + + return response.results[0] as CurationSuggestion; +}; + +const getSuggestion = async ( http: HttpSetup, engineName: string, query: string -): Promise => { +): Promise => { const response = await http.post( `/internal/app_search/engines/${engineName}/search_relevance_suggestions/${query}`, { @@ -140,6 +290,18 @@ const getSuggestions = async ( } ); + if (response.results.length < 1) { + const message = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.notFoundError', + { + defaultMessage: 'Could not find suggestion, it may have already been applied or rejected.', + } + ); + setQueuedErrorMessage(message); + KibanaLogic.values.navigateToUrl(generateEnginePath(ENGINE_CURATIONS_PATH)); + return; + } + const suggestion = response.results[0] as CurationSuggestion; return suggestion; }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.test.tsx index 04f05349217c07..e17b9263bb49d3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.test.tsx @@ -34,7 +34,11 @@ describe('DataPanel', () => { wrapper.setProps({ children: 'hello world' }); - expect(wrapper.find(EuiSpacer)).toHaveLength(1); + expect(wrapper.find(EuiSpacer).prop('size')).toEqual('s'); + + wrapper.setProps({ filled: true }); + + expect(wrapper.find(EuiSpacer).prop('size')).toEqual('l'); }); describe('components', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.tsx index 4b22fbc93d4119..8dc43d08e5e096 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.tsx @@ -87,7 +87,7 @@ export const DataPanel: React.FC = ({ {children && ( <> - + {children} )} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.test.tsx index cdd43c3efd97a9..f51087844e8885 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.test.tsx @@ -9,6 +9,10 @@ import React from 'react'; import { shallow } from 'enzyme'; +import { EuiBadge } from '@elastic/eui'; + +import { mountWithIntl } from '../../../test_helpers'; + import { ResultActions } from './result_actions'; import { ResultHeader } from './result_header'; @@ -46,6 +50,13 @@ describe('ResultHeader', () => { ); }); + it('renders position if one is passed in', () => { + const wrapper = mountWithIntl(); + + const badge = wrapper.find(EuiBadge); + expect(badge.text()).toContain('#5'); + }); + describe('score', () => { it('renders score if showScore is true ', () => { const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.tsx index fd524e126b2585..05af34c3fe3afa 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.tsx @@ -43,7 +43,7 @@ export const ResultHeader: React.FC = ({ responsive={false} wrap > - {resultPosition && ( + {typeof resultPosition !== 'undefined' && ( ( + +); diff --git a/x-pack/plugins/fleet/common/constants/epm.ts b/x-pack/plugins/fleet/common/constants/epm.ts index 81ea2a630d3db8..e482db6ae73abc 100644 --- a/x-pack/plugins/fleet/common/constants/epm.ts +++ b/x-pack/plugins/fleet/common/constants/epm.ts @@ -53,5 +53,7 @@ export const monitoringTypes = Object.values(dataTypes); export const installationStatuses = { Installed: 'installed', + Installing: 'installing', + InstallFailed: 'install_failed', NotInstalled: 'not_installed', } as const; diff --git a/x-pack/plugins/fleet/common/openapi/bundled.json b/x-pack/plugins/fleet/common/openapi/bundled.json index c58d064006a2b5..a9e92e3fc293a7 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.json +++ b/x-pack/plugins/fleet/common/openapi/bundled.json @@ -181,6 +181,8 @@ "type": "string", "enum": [ "installed", + "installing", + "install_failed", "not_installed" ] }, diff --git a/x-pack/plugins/fleet/common/openapi/bundled.yaml b/x-pack/plugins/fleet/common/openapi/bundled.yaml index 5a5b9838885aea..b997e31f4bb8d0 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.yaml +++ b/x-pack/plugins/fleet/common/openapi/bundled.yaml @@ -119,6 +119,8 @@ paths: type: string enum: - installed + - installing + - install_failed - not_installed savedObject: type: string diff --git a/x-pack/plugins/fleet/common/openapi/paths/epm@packages@{pkgkey}.yaml b/x-pack/plugins/fleet/common/openapi/paths/epm@packages@{pkgkey}.yaml index 1b15ddc4b22a3a..e82d9053b0e093 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/epm@packages@{pkgkey}.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/epm@packages@{pkgkey}.yaml @@ -17,6 +17,8 @@ get: type: string enum: - installed + - installing + - install_failed - not_installed savedObject: type: string diff --git a/x-pack/plugins/fleet/common/types/models/epm.ts b/x-pack/plugins/fleet/common/types/models/epm.ts index 20f41174a98475..1325d74f82b688 100644 --- a/x-pack/plugins/fleet/common/types/models/epm.ts +++ b/x-pack/plugins/fleet/common/types/models/epm.ts @@ -45,7 +45,7 @@ export interface DefaultPackagesInstallationError { export type InstallType = 'reinstall' | 'reupdate' | 'rollback' | 'update' | 'install' | 'unknown'; export type InstallSource = 'registry' | 'upload'; -export type EpmPackageInstallStatus = 'installed' | 'installing'; +export type EpmPackageInstallStatus = 'installed' | 'installing' | 'install_failed'; export type DetailViewPanelName = 'overview' | 'policies' | 'assets' | 'settings' | 'custom'; export type ServiceName = 'kibana' | 'elasticsearch'; @@ -399,17 +399,26 @@ export interface PackageUsageStats { agent_policy_count: number; } -export type Installable = Installed | NotInstalled; +export type Installable = Installed | Installing | NotInstalled | InstallFailed; export type Installed = T & { status: InstallationStatus['Installed']; savedObject: SavedObject; }; +export type Installing = T & { + status: InstallationStatus['Installing']; + savedObject: SavedObject; +}; + export type NotInstalled = T & { status: InstallationStatus['NotInstalled']; }; +export type InstallFailed = T & { + status: InstallationStatus['InstallFailed']; +}; + export type AssetReference = KibanaAssetReference | EsAssetReference; export type KibanaAssetReference = Pick & { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index 35092cb67f7ef7..7a2f46247d14af 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -584,10 +584,17 @@ export const EditPackagePolicyForm = memo<{ fill data-test-subj="saveIntegration" > - + {isUpgrade ? ( + + ) : ( + + )}
diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx index ac83cc83b68496..109f7500f160b2 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx @@ -38,6 +38,7 @@ export interface ListProps { setSelectedCategory: (category: string) => void; onSearchChange: (search: string) => void; showMissingIntegrationMessage?: boolean; + callout?: JSX.Element | null; } export function PackageListGrid({ @@ -49,6 +50,7 @@ export function PackageListGrid({ onSearchChange, setSelectedCategory, showMissingIntegrationMessage = false, + callout, }: ListProps) { const [searchTerm, setSearchTerm] = useState(initialSearch || ''); const localSearchRef = useLocalSearch(list); @@ -105,6 +107,7 @@ export function PackageListGrid({ }} onChange={onQueryChange} /> + {callout ? callout : null} {gridContent} {showMissingIntegrationMessage && ( diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx index 62225d14d38571..06cf85699bf673 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx @@ -5,10 +5,13 @@ * 2.0. */ -import React, { memo, useMemo } from 'react'; +import React, { memo, useMemo, Fragment } from 'react'; import { Switch, Route, useLocation, useHistory, useParams } from 'react-router-dom'; import semverLt from 'semver/functions/lt'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui'; import { installationStatuses } from '../../../../../../../common/constants'; import type { DynamicPage, DynamicPagePathValues, StaticPage } from '../../../../constants'; @@ -24,6 +27,7 @@ import { useGetAppendCustomIntegrations, useGetReplacementCustomIntegrations, useLink, + useStartServices, } from '../../../../hooks'; import { doesPackageHaveIntegrations } from '../../../../services'; import { DefaultLayout } from '../../../../layouts'; @@ -143,6 +147,7 @@ const InstalledPackages: React.FC = memo(() => { experimental: true, }); const { getHref, getAbsolutePath } = useLink(); + const { docLinks } = useStartServices(); const { selectedCategory, searchParam } = getParams( useParams(), @@ -225,6 +230,38 @@ const InstalledPackages: React.FC = memo(() => { return mapToCard(getAbsolutePath, getHref, item); }); + const link = ( + + {i18n.translate('xpack.fleet.epmList.availableCalloutBlogText', { + defaultMessage: 'announcement blog post', + })} + + ); + const calloutMessage = ( + + ); + + const callout = + selectedCategory === 'updates_available' ? null : ( + + + +

{calloutMessage}

+
+
+ ); + return ( { initialSearch={searchParam} title={title} list={cards} + callout={callout} /> ); }); diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/default_settings.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/default_settings.test.ts index 30f2909b2403ef..feab9cb8823936 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/default_settings.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/default_settings.test.ts @@ -46,6 +46,11 @@ describe('buildDefaultSettings', () => { "lifecycle": Object { "name": "logs", }, + "mapping": Object { + "total_fields": Object { + "limit": "10000", + }, + }, "query": Object { "default_field": Array [ "field1Keyword", diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/default_settings.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/default_settings.ts index a9ae65e9e97b89..84ec75b9da0651 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/default_settings.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/default_settings.ts @@ -67,6 +67,11 @@ export function buildDefaultSettings({ }, // What should be our default for the compression? codec: 'best_compression', + mapping: { + total_fields: { + limit: '10000', + }, + }, // All the default fields which should be queried have to be added here. // So far we add all keyword and text fields here if there are any, otherwise 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 9be22e76184665..76e01ed8b2f279 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 @@ -5,23 +5,30 @@ * 2.0. */ +jest.mock('../registry'); + import type { SavedObjectsClientContract, SavedObjectsFindResult } from 'kibana/server'; +import { SavedObjectsErrorHelpers } from '../../../../../../../src/core/server'; import { savedObjectsClientMock } from '../../../../../../../src/core/server/mocks'; -import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../common'; -import type { PackagePolicySOAttributes } from '../../../../common'; +import { PACKAGES_SAVED_OBJECT_TYPE, PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../common'; +import type { PackagePolicySOAttributes, RegistryPackage } from '../../../../common'; -import { getPackageUsageStats } from './get'; +import * as Registry from '../registry'; -describe('When using EPM `get` services', () => { - let soClient: jest.Mocked; +import { createAppContextStartContractMock } from '../../../mocks'; +import { appContextService } from '../../app_context'; - beforeEach(() => { - soClient = savedObjectsClientMock.create(); - }); +import { getPackageInfo, getPackageUsageStats } from './get'; +const MockRegistry = Registry as jest.Mocked; + +describe('When using EPM `get` services', () => { describe('and invoking getPackageUsageStats()', () => { + let soClient: jest.Mocked; + beforeEach(() => { + soClient = savedObjectsClientMock.create(); const savedObjects: Array> = [ { type: 'ingest-package-policies', @@ -172,4 +179,105 @@ describe('When using EPM `get` services', () => { }); }); }); + + describe('getPackageInfo', () => { + beforeEach(() => { + const mockContract = createAppContextStartContractMock(); + appContextService.start(mockContract); + MockRegistry.fetchFindLatestPackage.mockResolvedValue({ + name: 'my-package', + version: '1.0.0', + } as RegistryPackage); + MockRegistry.getRegistryPackage.mockResolvedValue({ + paths: [], + packageInfo: { + name: 'my-package', + version: '1.0.0', + } as RegistryPackage, + }); + }); + + describe('installation status', () => { + it('should be not_installed when no package SO exists', async () => { + const soClient = savedObjectsClientMock.create(); + soClient.get.mockRejectedValue(SavedObjectsErrorHelpers.createGenericNotFoundError()); + + expect( + await getPackageInfo({ + savedObjectsClient: soClient, + pkgName: 'my-package', + pkgVersion: '1.0.0', + }) + ).toMatchObject({ + status: 'not_installed', + }); + }); + + it('should be installing when package SO install_status is installing', async () => { + const soClient = savedObjectsClientMock.create(); + soClient.get.mockResolvedValue({ + id: 'my-package', + type: PACKAGES_SAVED_OBJECT_TYPE, + references: [], + attributes: { + install_status: 'installing', + }, + }); + + expect( + await getPackageInfo({ + savedObjectsClient: soClient, + pkgName: 'my-package', + pkgVersion: '1.0.0', + }) + ).toMatchObject({ + status: 'installing', + }); + }); + + it('should be installed when package SO install_status is installed', async () => { + const soClient = savedObjectsClientMock.create(); + soClient.get.mockResolvedValue({ + id: 'my-package', + type: PACKAGES_SAVED_OBJECT_TYPE, + references: [], + attributes: { + install_status: 'installed', + }, + }); + + expect( + await getPackageInfo({ + savedObjectsClient: soClient, + pkgName: 'my-package', + pkgVersion: '1.0.0', + }) + ).toMatchObject({ + status: 'installed', + }); + }); + + it('should be install_failed when package SO install_status is install_failed', async () => { + const soClient = savedObjectsClientMock.create(); + soClient.get.mockResolvedValue({ + id: 'my-package', + type: PACKAGES_SAVED_OBJECT_TYPE, + references: [], + attributes: { + install_status: 'install_failed', + }, + }); + + expect( + await getPackageInfo({ + savedObjectsClient: soClient, + pkgName: 'my-package', + pkgVersion: '1.0.0', + }) + ).toMatchObject({ + status: 'install_failed', + }); + }); + }); + }); }); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/index.ts b/x-pack/plugins/fleet/server/services/epm/packages/index.ts index 1f9113590f0f77..58e7c9e8928d88 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/index.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/index.ts @@ -53,7 +53,7 @@ export function createInstallableFrom( return savedObject ? { ...from, - status: installationStatuses.Installed, + status: savedObject.attributes.install_status, savedObject, } : { diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install.ts b/x-pack/plugins/fleet/server/services/epm/packages/install.ts index e71ef5e002884b..df28c041ba4779 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install.ts @@ -12,7 +12,12 @@ import type { ElasticsearchClient, SavedObject, SavedObjectsClientContract } fro import { generateESIndexPatterns } from '../elasticsearch/template/template'; -import type { BulkInstallPackageInfo, InstallablePackage, InstallSource } from '../../../../common'; +import type { + BulkInstallPackageInfo, + EpmPackageInstallStatus, + InstallablePackage, + InstallSource, +} from '../../../../common'; import { IngestManagerError, PackageOperationNotSupportedError, @@ -158,6 +163,8 @@ export async function handleInstallPackageFailure({ await removeInstallation({ savedObjectsClient, pkgkey, esClient }); } + await updateInstallStatus({ savedObjectsClient, pkgName, status: 'install_failed' }); + if (installType === 'update') { if (!installedPkg) { logger.error( @@ -432,6 +439,21 @@ export const updateVersion = async ( version: pkgVersion, }); }; + +export const updateInstallStatus = async ({ + savedObjectsClient, + pkgName, + status, +}: { + savedObjectsClient: SavedObjectsClientContract; + pkgName: string; + status: EpmPackageInstallStatus; +}) => { + return savedObjectsClient.update(PACKAGES_SAVED_OBJECT_TYPE, pkgName, { + install_status: status, + }); +}; + export async function createInstallation(options: { savedObjectsClient: SavedObjectsClientContract; packageInfo: InstallablePackage; diff --git a/x-pack/plugins/fleet/storybook/context/doc_links.ts b/x-pack/plugins/fleet/storybook/context/doc_links.ts new file mode 100644 index 00000000000000..56287dd9116a90 --- /dev/null +++ b/x-pack/plugins/fleet/storybook/context/doc_links.ts @@ -0,0 +1,21 @@ +/* + * 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 { DocLinksStart } from 'kibana/public'; + +export const getDocLinks = () => { + const docLinks: DocLinksStart = { + links: { + fleet: { + learnMoreBlog: + 'https://www.elastic.co/blog/elastic-agent-and-fleet-make-it-easier-to-integrate-your-systems-with-elastic', + }, + }, + } as unknown as DocLinksStart; + + return docLinks; +}; diff --git a/x-pack/plugins/fleet/storybook/context/index.tsx b/x-pack/plugins/fleet/storybook/context/index.tsx index e5a360c28385b0..6d563346e917d1 100644 --- a/x-pack/plugins/fleet/storybook/context/index.tsx +++ b/x-pack/plugins/fleet/storybook/context/index.tsx @@ -27,6 +27,7 @@ import { getHttp } from './http'; import { getUiSettings } from './ui_settings'; import { getNotifications } from './notifications'; import { stubbedStartServices } from './stubs'; +import { getDocLinks } from './doc_links'; // TODO: clintandrewhall - this is not ideal, or complete. The root context of Fleet applications // requires full start contracts of its dependencies. As a result, we have to mock all of those contracts @@ -42,8 +43,10 @@ export const StorybookContext: React.FC<{ storyContext?: StoryContext }> = ({ const history = new ScopedHistory(browserHistory, basepath); const startServices: FleetStartServices = { + ...stubbedStartServices, application: getApplication(), chrome: getChrome(), + docLinks: getDocLinks(), http: getHttp(), notifications: getNotifications(), uiSettings: getUiSettings(), @@ -58,7 +61,6 @@ export const StorybookContext: React.FC<{ storyContext?: StoryContext }> = ({ customIntegrations: { ContextProvider: getStorybookContextProvider(), }, - ...stubbedStartServices, }; setHttpClient(startServices.http); diff --git a/x-pack/plugins/fleet/storybook/context/stubs.tsx b/x-pack/plugins/fleet/storybook/context/stubs.tsx index 54ae18b083a2fe..a7db4bd8f68cd0 100644 --- a/x-pack/plugins/fleet/storybook/context/stubs.tsx +++ b/x-pack/plugins/fleet/storybook/context/stubs.tsx @@ -9,7 +9,6 @@ import type { FleetStartServices } from '../../public/plugin'; type Stubs = | 'storage' - | 'docLinks' | 'data' | 'deprecations' | 'fatalErrors' @@ -22,7 +21,6 @@ type StubbedStartServices = Pick; export const stubbedStartServices: StubbedStartServices = { storage: {} as FleetStartServices['storage'], - docLinks: {} as FleetStartServices['docLinks'], data: {} as FleetStartServices['data'], deprecations: {} as FleetStartServices['deprecations'], fatalErrors: {} as FleetStartServices['fatalErrors'], diff --git a/x-pack/plugins/lens/public/app_plugin/mounter.tsx b/x-pack/plugins/lens/public/app_plugin/mounter.tsx index a470bf9c1a4053..d4bc59a1e9e2ca 100644 --- a/x-pack/plugins/lens/public/app_plugin/mounter.tsx +++ b/x-pack/plugins/lens/public/app_plugin/mounter.tsx @@ -6,7 +6,7 @@ */ import React, { FC, useCallback } from 'react'; -import { DeepPartial } from '@reduxjs/toolkit'; +import { PreloadedState } from '@reduxjs/toolkit'; import { AppMountParameters, CoreSetup, CoreStart } from 'kibana/public'; import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; import { HashRouter, Route, RouteComponentProps, Switch } from 'react-router-dom'; @@ -193,7 +193,7 @@ export async function mountApp( const emptyState = getPreloadedState(storeDeps) as LensAppState; const lensStore: LensRootStore = makeConfigureStore(storeDeps, { lens: emptyState, - } as DeepPartial); + } as PreloadedState); const EditorRenderer = React.memo( (props: { id?: string; history: History; editByValue?: boolean }) => { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/add_layer.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/add_layer.tsx index b0c10abb75810f..e052e06f1b2f16 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/add_layer.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/add_layer.tsx @@ -57,7 +57,7 @@ export function AddLayerButton({ })} content={i18n.translate('xpack.lens.xyChart.addLayerTooltip', { defaultMessage: - 'Use multiple layers to combine visualization types or visualize different data views.', + 'Use multiple layers to combine visualization types or visualize different index patterns.', })} position="bottom" > diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index f1161b83c228ec..e4816870b43806 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -151,9 +151,9 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ ? [ { shortMessage: '', - longMessage: i18n.translate('xpack.lens.indexPattern.missingDataView', { + longMessage: i18n.translate('xpack.lens.indexPattern.missingIndexPattern', { defaultMessage: - 'The {count, plural, one {data view} other {data views}} ({count, plural, one {id} other {ids}}: {indexpatterns}) cannot be found', + 'The {count, plural, one {index pattern} other {index patterns}} ({count, plural, one {id} other {ids}}: {indexpatterns}) cannot be found', values: { count: missingIndexPatterns.length, indexpatterns: missingIndexPatterns.join(', '), @@ -569,8 +569,8 @@ export const VisualizationWrapper = ({ })} data-test-subj="configuration-failure-reconfigure-indexpatterns" > - {i18n.translate('xpack.lens.editorFrame.dataViewReconfigure', { - defaultMessage: `Recreate it in the data view management page`, + {i18n.translate('xpack.lens.editorFrame.indexPatternReconfigure', { + defaultMessage: `Recreate it in the index pattern management page`, })} @@ -580,8 +580,8 @@ export const VisualizationWrapper = ({ <>

diff --git a/x-pack/plugins/lens/public/editor_frame_service/error_helper.ts b/x-pack/plugins/lens/public/editor_frame_service/error_helper.ts index 9df48d99ce7624..b19a295b684071 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/error_helper.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/error_helper.ts @@ -160,8 +160,9 @@ export function getMissingCurrentDatasource() { } export function getMissingIndexPatterns(indexPatternIds: string[]) { - return i18n.translate('xpack.lens.editorFrame.expressionMissingDataView', { - defaultMessage: 'Could not find the {count, plural, one {data view} other {data views}}: {ids}', + return i18n.translate('xpack.lens.editorFrame.expressionMissingIndexPattern', { + defaultMessage: + 'Could not find the {count, plural, one {index pattern} other {index pattern}}: {ids}', values: { count: indexPatternIds.length, ids: indexPatternIds.join(', ') }, }); } diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx index eea54ed525f6c1..4c247c031eac08 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx @@ -236,7 +236,7 @@ describe('embeddable', () => { ...savedVis, sharingSavedObjectProps: { outcome: 'conflict', - errorJSON: '{targetType: "lens", sourceId: "1", targetSpace: "space"}', + sourceId: '1', aliasTargetId: '2', }, } as ResolvedLensSavedObjectAttributes); diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx index 2e0ab2401c70f9..7faf873cf0b0a9 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.tsx @@ -286,8 +286,9 @@ export class Embeddable defaultMessage: `You've encountered a URL conflict`, }), longMessage: ( - ), }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/change_indexpattern.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/change_indexpattern.tsx index ca44e833981ab4..64d7f5efc9c4d6 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/change_indexpattern.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/change_indexpattern.tsx @@ -69,8 +69,8 @@ export function ChangeIndexPattern({ >

- {i18n.translate('xpack.lens.indexPattern.changeDataViewTitle', { - defaultMessage: 'Data view', + {i18n.translate('xpack.lens.indexPattern.changeIndexPatternTitle', { + defaultMessage: 'Index pattern', })}

@@ -642,7 +642,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ iconType="boxesHorizontal" data-test-subj="lnsIndexPatternActions" aria-label={i18n.translate('xpack.lens.indexPatterns.actionsPopoverLabel', { - defaultMessage: 'Data view settings', + defaultMessage: 'Index pattern settings', })} onClick={() => { setPopoverOpen(!popoverOpen); @@ -663,7 +663,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ }} > {i18n.translate('xpack.lens.indexPatterns.addFieldButton', { - defaultMessage: 'Add field to data view', + defaultMessage: 'Add field to index pattern', })} , {i18n.translate('xpack.lens.indexPatterns.manageFieldButton', { - defaultMessage: 'Manage data view fields', + defaultMessage: 'Manage index pattern fields', })} , ]} @@ -709,7 +709,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ data-test-subj="lnsIndexPatternFieldSearch" placeholder={i18n.translate('xpack.lens.indexPatterns.filterByNameLabel', { defaultMessage: 'Search field names', - description: 'Search the list of fields in the data view for the provided text', + description: 'Search the list of fields in the index pattern for the provided text', })} value={localState.nameFilter} onChange={(e) => { @@ -717,7 +717,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ }} aria-label={i18n.translate('xpack.lens.indexPatterns.filterByNameLabel', { defaultMessage: 'Search field names', - description: 'Search the list of fields in the data view for the provided text', + description: 'Search the list of fields in the index pattern for the provided text', })} aria-describedby={fieldSearchDescriptionId} /> diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimensions_editor_helpers.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimensions_editor_helpers.tsx index dc6dc6dc31c865..a39f3705fd230a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimensions_editor_helpers.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimensions_editor_helpers.tsx @@ -217,7 +217,7 @@ export function getErrorMessage( } if (fieldInvalid) { return i18n.translate('xpack.lens.indexPattern.invalidFieldLabel', { - defaultMessage: 'Invalid field. Check your data view or pick another field.', + defaultMessage: 'Invalid field. Check your index pattern or pick another field.', }); } } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx index ee6065aabf9d1f..9c22ec9d4bb05b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx @@ -348,7 +348,7 @@ function FieldPanelHeader({ @@ -366,7 +366,7 @@ function FieldPanelHeader({ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx index c408d0130825b5..2138b06a4c3447 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx @@ -98,8 +98,8 @@ export function getIndexPatternDatasource({ const uiSettings = core.uiSettings; const onIndexPatternLoadError = (err: Error) => core.notifications.toasts.addError(err, { - title: i18n.translate('xpack.lens.indexPattern.dataViewLoadError', { - defaultMessage: 'Error loading data view', + title: i18n.translate('xpack.lens.indexPattern.indexPatternLoadError', { + defaultMessage: 'Error loading index pattern', }), }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.tsx index 28f2921ccc771a..12536e556f306d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.tsx @@ -23,8 +23,8 @@ export function LayerPanel({ state, layerId, onChangeIndexPattern }: IndexPatter const indexPattern = state.indexPatterns[layer.indexPatternId]; - const notFoundTitleLabel = i18n.translate('xpack.lens.layerPanel.missingDataView', { - defaultMessage: 'Data view not found', + const notFoundTitleLabel = i18n.translate('xpack.lens.layerPanel.missingIndexPattern', { + defaultMessage: 'Index pattern not found', }); return ( diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.test.tsx index 635c06691a7339..69dc150922b4a3 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.test.tsx @@ -16,7 +16,7 @@ describe('NoFieldCallout', () => { `); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.tsx index 073b21c700ccc8..6b434e8cd41a6d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.tsx @@ -32,7 +32,7 @@ export const NoFieldsCallout = ({ size="s" color="warning" title={i18n.translate('xpack.lens.indexPatterns.noFieldsLabel', { - defaultMessage: 'No fields exist in this data view.', + defaultMessage: 'No fields exist in this index pattern.', })} /> ); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.test.tsx index d0dd8a438ed1c2..77af42ab418883 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.test.tsx @@ -343,7 +343,7 @@ describe('last_value', () => { 'data' ); expect(disabledStatus).toEqual( - 'This function requires the presence of a date field in your data view' + 'This function requires the presence of a date field in your index' ); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx index 9a3ba9a044148e..88c9d82092e216 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx @@ -134,7 +134,7 @@ export const lastValueOperation: OperationDefinition @@ -284,7 +284,7 @@ export const lastValueOperation: OperationDefinition); + } as PreloadedState); const origDispatch = store.dispatch; store.dispatch = jest.fn(dispatch || origDispatch); diff --git a/x-pack/plugins/lens/public/state_management/index.ts b/x-pack/plugins/lens/public/state_management/index.ts index cc83cc612f32d5..0aa7185931c5af 100644 --- a/x-pack/plugins/lens/public/state_management/index.ts +++ b/x-pack/plugins/lens/public/state_management/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { configureStore, getDefaultMiddleware, DeepPartial } from '@reduxjs/toolkit'; +import { configureStore, getDefaultMiddleware, PreloadedState } from '@reduxjs/toolkit'; import { createLogger } from 'redux-logger'; import { useDispatch, useSelector, TypedUseSelectorHook } from 'react-redux'; import { makeLensReducer, lensActions } from './lens_slice'; @@ -36,7 +36,7 @@ export const { export const makeConfigureStore = ( storeDeps: LensStoreDeps, - preloadedState: DeepPartial + preloadedState: PreloadedState ) => { const middleware = [ ...getDefaultMiddleware({ diff --git a/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts b/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts index 314434a16af8c4..5c571c750a4aa5 100644 --- a/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts +++ b/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts @@ -27,7 +27,7 @@ export const getPersisted = async ({ lensServices: LensAppServices; history?: History; }): Promise< - { doc: Document; sharingSavedObjectProps: Omit } | undefined + { doc: Document; sharingSavedObjectProps: Omit } | undefined > => { const { notifications, spaces, attributeService } = lensServices; let doc: Document; diff --git a/x-pack/plugins/lens/public/state_management/types.ts b/x-pack/plugins/lens/public/state_management/types.ts index c15b29d0040d03..e46c685925b20c 100644 --- a/x-pack/plugins/lens/public/state_management/types.ts +++ b/x-pack/plugins/lens/public/state_management/types.ts @@ -43,7 +43,7 @@ export interface LensAppState extends EditorFrameState { savedQuery?: SavedQuery; searchSessionId: string; resolvedDateRange: DateRange; - sharingSavedObjectProps?: Omit; + sharingSavedObjectProps?: Omit; } export type DispatchSetState = (state: Partial) => { diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 2e7876f83fc418..87e2762149acd2 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -834,5 +834,5 @@ export interface ILensInterpreterRenderHandlers extends IInterpreterRenderHandle export interface SharingSavedObjectProps { outcome?: 'aliasMatch' | 'exactMatch' | 'conflict'; aliasTargetId?: string; - errorJSON?: string; + sourceId?: string; } diff --git a/x-pack/plugins/lens/server/routes/field_stats.ts b/x-pack/plugins/lens/server/routes/field_stats.ts index 88e8e600aa906b..7103e395eabdc3 100644 --- a/x-pack/plugins/lens/server/routes/field_stats.ts +++ b/x-pack/plugins/lens/server/routes/field_stats.ts @@ -56,7 +56,7 @@ export async function initFieldsRoute(setup: CoreSetup) { const field = indexPattern.fields.find((f) => f.name === fieldName); if (!field) { - throw new Error(`Field {fieldName} not found in data view ${indexPattern.title}`); + throw new Error(`Field {fieldName} not found in index pattern ${indexPattern.title}`); } const filter = timeFieldName diff --git a/x-pack/plugins/license_management/__jest__/__snapshots__/upload_license.test.tsx.snap b/x-pack/plugins/license_management/__jest__/__snapshots__/upload_license.test.tsx.snap index 6591afafff00ff..db9647d03f8e27 100644 --- a/x-pack/plugins/license_management/__jest__/__snapshots__/upload_license.test.tsx.snap +++ b/x-pack/plugins/license_management/__jest__/__snapshots__/upload_license.test.tsx.snap @@ -156,11 +156,11 @@ exports[`UploadLicense should display a modal when license requires acknowledgem @@ -1108,11 +1108,11 @@ exports[`UploadLicense should display an error when ES says license is expired 1 @@ -1820,11 +1820,11 @@ exports[`UploadLicense should display an error when ES says license is invalid 1 @@ -2532,11 +2532,11 @@ exports[`UploadLicense should display an error when submitting invalid JSON 1`] @@ -3244,11 +3244,11 @@ exports[`UploadLicense should display error when ES returns error 1`] = ` diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index b0daace7afa9ee..d15a3efc5375da 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -364,8 +364,9 @@ export class MapEmbeddable iconType="alert" iconColor="danger" data-test-subj="embeddable-maps-failure" - body={spaces.ui.components.getSavedObjectConflictMessage({ - json: sharingSavedObjectProps.errorJSON!, + body={spaces.ui.components.getEmbeddableLegacyUrlConflict({ + targetType: MAP_SAVED_OBJECT_TYPE, + sourceId: sharingSavedObjectProps.sourceId!, })} />
diff --git a/x-pack/plugins/maps/public/map_attribute_service.ts b/x-pack/plugins/maps/public/map_attribute_service.ts index ab380ca5a6b66d..85d4d73da82cde 100644 --- a/x-pack/plugins/maps/public/map_attribute_service.ts +++ b/x-pack/plugins/maps/public/map_attribute_service.ts @@ -14,12 +14,11 @@ import { checkForDuplicateTitle, OnSaveProps } from '../../../../src/plugins/sav import { getCoreOverlays, getEmbeddableService, getSavedObjectsClient } from './kibana_services'; import { extractReferences, injectReferences } from '../common/migrations/references'; import { MapByValueInput, MapByReferenceInput } from './embeddable/types'; -import { getSpacesApi } from './kibana_services'; export interface SharingSavedObjectProps { outcome?: 'aliasMatch' | 'exactMatch' | 'conflict'; aliasTargetId?: string; - errorJSON?: string; + sourceId?: string; } type MapDoc = MapSavedObjectAttributes & { @@ -88,14 +87,7 @@ export function getMapAttributeService(): MapAttributeService { sharingSavedObjectProps: { aliasTargetId, outcome, - errorJSON: - outcome === 'conflict' && getSpacesApi() - ? JSON.stringify({ - targetType: MAP_SAVED_OBJECT_TYPE, - sourceId: savedObjectId, - targetSpace: (await getSpacesApi()!.getActiveSpace()).id, - }) - : undefined, + sourceId: savedObjectId, }, }; }, diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_name.test.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_name.test.tsx index 696eeefa6cc1a3..6b26e3823d2efa 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_name.test.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_name.test.tsx @@ -69,7 +69,7 @@ describe('DeleteAction', () => { }); describe('When delete model is open', () => { - it('should allow to delete target index by default.', () => { + it('should not allow to delete target index by default.', () => { const mock = jest.spyOn(CheckPrivilige, 'checkPermission'); mock.mockImplementation((p) => p === 'canDeleteDataFrameAnalytics'); @@ -101,10 +101,9 @@ describe('DeleteAction', () => { const deleteButton = getByTestId('mlAnalyticsJobDeleteButton'); fireEvent.click(deleteButton); expect(getByTestId('mlAnalyticsJobDeleteModal')).toBeInTheDocument(); - expect(getByTestId('mlAnalyticsJobDeleteIndexSwitch')).toBeInTheDocument(); - const mlAnalyticsJobDeleteIndexSwitch = getByTestId('mlAnalyticsJobDeleteIndexSwitch'); - expect(mlAnalyticsJobDeleteIndexSwitch).toHaveAttribute('aria-checked', 'true'); + expect(queryByTestId('mlAnalyticsJobDeleteIndexSwitch')).toBeNull(); expect(queryByTestId('mlAnalyticsJobDeleteIndexPatternSwitch')).toBeNull(); + mock.mockRestore(); }); }); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx index 4abe70435d37c5..91871015d2adde 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx @@ -89,9 +89,9 @@ export const useDeleteAction = (canDeleteDataFrameAnalytics: boolean) => { ); } }; - const checkUserIndexPermission = () => { + const checkUserIndexPermission = async () => { try { - const userCanDelete = canDeleteIndex(indexName, toastNotificationService); + const userCanDelete = await canDeleteIndex(indexName, toastNotificationService); if (userCanDelete) { setUserCanDeleteIndex(true); } diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/delete_models_modal.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/delete_models_modal.tsx index d93baee97c5330..0db4c5d30fbeb6 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/delete_models_modal.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/delete_models_modal.tsx @@ -30,7 +30,11 @@ export const DeleteModelsModal: FC = ({ models, onClose .map((model) => model.model_id); return ( - + = ({ models, onClose /> - + { description: i18n.translate('xpack.ml.trainedModels.modelsList.deleteModelActionLabel', { defaultMessage: 'Delete model', }), + 'data-test-subj': 'mlModelsTableRowDeleteAction', icon: 'trash', type: 'icon', color: 'danger', @@ -353,7 +355,7 @@ export const ModelsList: FC = () => { enabled: (item) => { // TODO check for permissions to delete ingest pipelines. // ATM undefined means pipelines fetch failed server-side. - return !item.pipelines; + return !isPopulatedObject(item.pipelines); }, }, ]; @@ -389,6 +391,7 @@ export const ModelsList: FC = () => { iconType={itemIdToExpandedRowMap[item.model_id] ? 'arrowUp' : 'arrowDown'} /> ), + 'data-test-subj': 'mlModelsTableRowDetailsToggle', }, { field: ModelsTableToConfigMapping.id, @@ -397,6 +400,7 @@ export const ModelsList: FC = () => { }), sortable: true, truncateText: true, + 'data-test-subj': 'mlModelsTableColumnId', }, { field: ModelsTableToConfigMapping.description, @@ -406,6 +410,7 @@ export const ModelsList: FC = () => { }), sortable: false, truncateText: true, + 'data-test-subj': 'mlModelsTableColumnDescription', }, { field: ModelsTableToConfigMapping.type, @@ -418,11 +423,14 @@ export const ModelsList: FC = () => { {types.map((type) => ( - {type} + + {type} + ))} ), + 'data-test-subj': 'mlModelsTableColumnType', }, { field: ModelsTableToConfigMapping.createdAt, @@ -432,12 +440,14 @@ export const ModelsList: FC = () => { dataType: 'date', render: timeFormatter, sortable: true, + 'data-test-subj': 'mlModelsTableColumnCreatedAt', }, { name: i18n.translate('xpack.ml.trainedModels.modelsList.actionsHeader', { defaultMessage: 'Actions', }), actions, + 'data-test-subj': 'mlModelsTableColumnActions', }, ]; @@ -492,8 +502,7 @@ export const ModelsList: FC = () => { defaultMessage: 'Select a model', }); } - - if (Array.isArray(item.pipelines) && item.pipelines.length > 0) { + if (isPopulatedObject(item.pipelines)) { return i18n.translate('xpack.ml.trainedModels.modelsList.disableSelectableMessage', { defaultMessage: 'Model has associated pipelines', }); @@ -507,7 +516,7 @@ export const ModelsList: FC = () => { return ''; }, - selectable: (item) => !item.pipelines && !isBuiltInModel(item), + selectable: (item) => !isPopulatedObject(item.pipelines) && !isBuiltInModel(item), onSelectionChange: (selectedItems) => { setSelectedModels(selectedItems); }, @@ -574,6 +583,7 @@ export const ModelsList: FC = () => { pagination={pagination} onTableChange={onTableChange} sorting={sorting} + data-test-subj={isLoading ? 'mlModelsTable loading' : 'mlModelsTable loaded'} />
{modelsToDelete.length > 0 && ( diff --git a/x-pack/plugins/monitoring/public/application/hooks/use_monitoring_time.ts b/x-pack/plugins/monitoring/public/application/hooks/use_monitoring_time.ts index e512f90d76e690..3054714ec3aa6f 100644 --- a/x-pack/plugins/monitoring/public/application/hooks/use_monitoring_time.ts +++ b/x-pack/plugins/monitoring/public/application/hooks/use_monitoring_time.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { useCallback, useState, useContext } from 'react'; +import { useCallback, useState, useContext, useEffect } from 'react'; import createContainer from 'constate'; import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; import { Legacy } from '../../legacy_shims'; @@ -53,6 +53,18 @@ export const useMonitoringTime = () => { [currentTimerange, setTimeRange, state] ); + useEffect(() => { + const sub = Legacy.shims.timefilter.getTimeUpdate$().subscribe(function onTimeUpdate() { + const updatedTime = Legacy.shims.timefilter.getTime(); + setTimeRange({ ...currentTimerange, ...updatedTime }); + state.time = { ...updatedTime }; + state.save?.(); + }); + + return () => sub.unsubscribe(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + return { currentTimerange, setTimeRange, diff --git a/x-pack/plugins/monitoring/public/application/index.tsx b/x-pack/plugins/monitoring/public/application/index.tsx index c81903fed5a31a..bc81dd826f8492 100644 --- a/x-pack/plugins/monitoring/public/application/index.tsx +++ b/x-pack/plugins/monitoring/public/application/index.tsx @@ -231,34 +231,12 @@ const MonitoringApp: React.FC<{ fetchAllClusters={false} /> - {/* APM Views */} - - - {/* Logstash Routes */} - - - + + {/* APM Views */} + + + + = ({ label: i18n.translate('xpack.monitoring.logstashNavigation.instance.overviewLinkText', { defaultMessage: 'Overview', }), - route: `/logstash/node/${instance.nodeSummary?.uuid}`, // IDK if this is right + route: `/logstash/node/${instance.nodeSummary?.uuid}`, }); tabs.push({ id: 'pipeline', label: i18n.translate('xpack.monitoring.logstashNavigation.instance.pipelinesLinkText', { defaultMessage: 'Pipelines', }), - route: `/logstash/node/${instance.nodeSummary?.uuid}/pipelines`, // IDK if this is right + route: `/logstash/node/${instance.nodeSummary?.uuid}/pipelines`, }); tabs.push({ id: 'advanced', label: i18n.translate('xpack.monitoring.logstashNavigation.instance.advancedLinkText', { defaultMessage: 'Advanced', }), - route: `/logstash/node/${instance.nodeSummary?.uuid}/advanced`, // IDK if this is right + route: `/logstash/node/${instance.nodeSummary?.uuid}/advanced`, }); } } diff --git a/x-pack/plugins/monitoring/public/components/shared/toolbar.tsx b/x-pack/plugins/monitoring/public/components/shared/toolbar.tsx index 7a7130007dad6f..32bbdd6ecbeda1 100644 --- a/x-pack/plugins/monitoring/public/components/shared/toolbar.tsx +++ b/x-pack/plugins/monitoring/public/components/shared/toolbar.tsx @@ -40,14 +40,8 @@ export const MonitoringToolbar: React.FC = ({ pageTitle, return; } handleTimeChange(selectedTime.start, selectedTime.end); - state.time = { - from: selectedTime.start, - to: selectedTime.end, - }; - Legacy.shims.timefilter.setTime(state.time); - state.save?.(); }, - [handleTimeChange, state] + [handleTimeChange] ); const onRefreshChange = useCallback( diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_storage.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_storage.test.tsx index ce6d7bd94d8e47..ffe7db05683444 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_storage.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_storage.test.tsx @@ -6,15 +6,17 @@ */ import React, { useEffect } from 'react'; +import { act, renderHook } from '@testing-library/react-hooks'; import { Route, Router } from 'react-router-dom'; import { render } from '@testing-library/react'; import { UrlStorageContextProvider, useSeriesStorage } from './use_series_storage'; import { getHistoryFromUrl } from '../rtl_helpers'; +import type { AppDataType } from '../types'; const mockSingleSeries = [ { name: 'performance-distribution', - dataType: 'ux', + dataType: 'ux' as AppDataType, breakdown: 'user_agent.name', time: { from: 'now-15m', to: 'now' }, }, @@ -23,13 +25,13 @@ const mockSingleSeries = [ const mockMultipleSeries = [ { name: 'performance-distribution', - dataType: 'ux', + dataType: 'ux' as AppDataType, breakdown: 'user_agent.name', time: { from: 'now-15m', to: 'now' }, }, { name: 'kpi-over-time', - dataType: 'synthetics', + dataType: 'synthetics' as AppDataType, breakdown: 'user_agent.name', time: { from: 'now-15m', to: 'now' }, }, @@ -92,7 +94,7 @@ describe('userSeriesStorage', function () { ); }); - it('should return expected result when there are multiple series series', function () { + it('should return expected result when there are multiple series', function () { const setData = setupTestComponent(mockMultipleSeries); expect(setData).toHaveBeenCalledTimes(2); @@ -133,4 +135,41 @@ describe('userSeriesStorage', function () { }) ); }); + + it('ensures that only one series has a breakdown', () => { + function wrapper({ children }: { children: React.ReactElement }) { + return ( + (key === 'sr' ? mockMultipleSeries : null)), + set: jest.fn(), + }} + > + {children} + + ); + } + const { result } = renderHook(() => useSeriesStorage(), { wrapper }); + + act(() => { + result.current.setSeries(1, mockMultipleSeries[1]); + }); + + expect(result.current.allSeries).toEqual([ + { + name: 'performance-distribution', + dataType: 'ux', + breakdown: 'user_agent.name', + time: { from: 'now-15m', to: 'now' }, + }, + { + name: 'kpi-over-time', + dataType: 'synthetics', + breakdown: undefined, + time: { from: 'now-15m', to: 'now' }, + }, + ]); + }); }); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_storage.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_storage.tsx index 85e166db94aaae..83042876db2ae7 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_storage.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_storage.tsx @@ -71,9 +71,16 @@ export function UrlStorageContextProvider({ const setSeries = useCallback((seriesIndex: number, newValue: SeriesUrl) => { setAllSeries((prevAllSeries) => { + const seriesWithCurrentBreakdown = prevAllSeries.findIndex((series) => series.breakdown); const newStateRest = prevAllSeries.map((series, index) => { if (index === seriesIndex) { - return newValue; + return { + ...newValue, + breakdown: + seriesWithCurrentBreakdown === seriesIndex || seriesWithCurrentBreakdown === -1 + ? newValue.breakdown + : undefined, + }; } return series; }); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.test.tsx index 21b766227a562d..cb683119384d90 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.test.tsx @@ -55,4 +55,24 @@ describe('Breakdowns', function () { }); expect(setSeries).toHaveBeenCalledTimes(1); }); + + it('should disable breakdowns when a different series has a breakdown', function () { + const initSeries = { + data: [mockUxSeries, { ...mockUxSeries, breakdown: undefined }], + breakdown: USER_AGENT_OS, + }; + + render( + , + { initSeries } + ); + + const button = screen.getByText('No breakdown'); + + expect(button).toHaveAttribute('disabled'); + }); }); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.tsx index cfd3d153a61c52..7964abdeeddc5a 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.tsx @@ -6,7 +6,8 @@ */ import React from 'react'; -import { EuiSuperSelect } from '@elastic/eui'; +import styled from 'styled-components'; +import { EuiSuperSelect, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { useSeriesStorage } from '../../hooks/use_series_storage'; import { LABEL_FIELDS_BREAKDOWN, USE_BREAK_DOWN_COLUMN } from '../../configurations/constants'; @@ -19,7 +20,14 @@ interface Props { } export function Breakdowns({ seriesConfig, seriesId, series }: Props) { - const { setSeries } = useSeriesStorage(); + const { setSeries, allSeries } = useSeriesStorage(); + + const indexOfSeriesWithBreakdown = allSeries.findIndex((seriesT) => { + return Boolean(seriesT.breakdown); + }); + const currentSeriesHasBreakdown = indexOfSeriesWithBreakdown === seriesId; + const anySeriesHasBreakdown = indexOfSeriesWithBreakdown !== -1; + const differentSeriesHasBreakdown = anySeriesHasBreakdown && !currentSeriesHasBreakdown; const selectedBreakdown = series.breakdown; const NO_BREAKDOWN = 'no_breakdown'; @@ -69,13 +77,28 @@ export function Breakdowns({ seriesConfig, seriesId, series }: Props) { valueOfSelected = LABEL_FIELDS_BREAKDOWN; } + function Select() { + return ( + onOptionChange(value)} + data-test-subj={'seriesBreakdown'} + disabled={differentSeriesHasBreakdown} + /> + ); + } + return ( - onOptionChange(value)} - data-test-subj={'seriesBreakdown'} - /> + + {differentSeriesHasBreakdown ? ( + + + )} + ); } @@ -85,3 +108,13 @@ export const NO_BREAK_DOWN_LABEL = i18n.translate( defaultMessage: 'No breakdown', } ); + +export const BREAKDOWN_WARNING = i18n.translate('xpack.observability.exp.breakDownFilter.warning', { + defaultMessage: 'Breakdowns can be applied to only one series at a time.', +}); + +const Wrapper = styled.span` + .euiToolTipAnchor { + width: 100%; + } +`; 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 202d52e749e64c..4578c159e809e1 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 @@ -148,14 +148,13 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo< // }, [editMode, replace]); const scheduledQueryGroupTableData = useMemo(() => { - const policyWithoutEmptyQueries = produce< - NewPackagePolicy, - OsqueryManagerPackagePolicy, - OsqueryManagerPackagePolicy - >(newPolicy, (draft) => { - draft.inputs[0].streams = filter(['compiled_stream.id', null], draft.inputs[0].streams); - return draft; - }); + const policyWithoutEmptyQueries = produce( + newPolicy, + (draft) => { + draft.inputs[0].streams = filter(['compiled_stream.id', null], draft.inputs[0].streams); + return draft; + } + ); return policyWithoutEmptyQueries; }, [newPolicy]); @@ -198,6 +197,7 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo< diff --git a/x-pack/plugins/osquery/public/packs/common/pack_queries_field.tsx b/x-pack/plugins/osquery/public/packs/common/pack_queries_field.tsx index fa29bf54e21ff9..6b3c1a001bd066 100644 --- a/x-pack/plugins/osquery/public/packs/common/pack_queries_field.tsx +++ b/x-pack/plugins/osquery/public/packs/common/pack_queries_field.tsx @@ -44,6 +44,7 @@ const PackQueriesFieldComponent = ({ field }) => { (newQuery) => setValue( produce((draft) => { + // @ts-expect-error update draft.push({ interval: newQuery.interval, query: newQuery.query.attributes.query, @@ -56,6 +57,7 @@ const PackQueriesFieldComponent = ({ field }) => { ); const handleRemoveQuery = useCallback( + // @ts-expect-error update (query) => setValue(produce((draft) => reject(['id', query.id], draft))), [setValue] ); diff --git a/x-pack/plugins/osquery/public/scheduled_query_groups/form/queries_field.tsx b/x-pack/plugins/osquery/public/scheduled_query_groups/form/queries_field.tsx index d4e8592b65bcbd..7eec37d62d52e4 100644 --- a/x-pack/plugins/osquery/public/scheduled_query_groups/form/queries_field.tsx +++ b/x-pack/plugins/osquery/public/scheduled_query_groups/form/queries_field.tsx @@ -138,33 +138,42 @@ const QueriesFieldComponent: React.FC = ({ if (showEditQueryFlyout >= 0) { setValue( produce((draft) => { + // @ts-expect-error update draft[0].streams[showEditQueryFlyout].vars.id.value = updatedQuery.id; + // @ts-expect-error update draft[0].streams[showEditQueryFlyout].vars.interval.value = updatedQuery.interval; + // @ts-expect-error update draft[0].streams[showEditQueryFlyout].vars.query.value = updatedQuery.query; if (updatedQuery.platform?.length) { + // @ts-expect-error update draft[0].streams[showEditQueryFlyout].vars.platform = { type: 'text', value: updatedQuery.platform, }; } else { + // @ts-expect-error update delete draft[0].streams[showEditQueryFlyout].vars.platform; } if (updatedQuery.version?.length) { + // @ts-expect-error update draft[0].streams[showEditQueryFlyout].vars.version = { type: 'text', value: updatedQuery.version, }; } else { + // @ts-expect-error update delete draft[0].streams[showEditQueryFlyout].vars.version; } if (updatedQuery.ecs_mapping) { + // @ts-expect-error update draft[0].streams[showEditQueryFlyout].vars.ecs_mapping = { value: updatedQuery.ecs_mapping, }; } else { + // @ts-expect-error update delete draft[0].streams[showEditQueryFlyout].vars.ecs_mapping; } @@ -185,6 +194,7 @@ const QueriesFieldComponent: React.FC = ({ setValue( produce((draft) => { draft[0].streams.push( + // @ts-expect-error update getNewStream({ ...newQuery, scheduledQueryGroupId, @@ -221,6 +231,7 @@ const QueriesFieldComponent: React.FC = ({ produce((draft) => { forEach(parsedContent.queries, (newQuery, newQueryId) => { draft[0].streams.push( + // @ts-expect-error update getNewStream({ id: isOsqueryPackSupported ? newQueryId : `pack_${packName}_${newQueryId}`, interval: newQuery.interval ?? parsedContent.interval, diff --git a/x-pack/plugins/osquery/public/scheduled_query_groups/queries/ecs_mapping_editor_field.tsx b/x-pack/plugins/osquery/public/scheduled_query_groups/queries/ecs_mapping_editor_field.tsx index 92f2cfa973ce8d..34d7dd755e2b9c 100644 --- a/x-pack/plugins/osquery/public/scheduled_query_groups/queries/ecs_mapping_editor_field.tsx +++ b/x-pack/plugins/osquery/public/scheduled_query_groups/queries/ecs_mapping_editor_field.tsx @@ -317,7 +317,7 @@ export interface ECSMappingEditorFieldRef { } export interface ECSMappingEditorFieldProps { - field: FieldHook; + field: FieldHook>; query: string; fieldRef: MutableRefObject; } diff --git a/x-pack/plugins/rule_registry/server/scripts/get_alerts_index.sh b/x-pack/plugins/rule_registry/server/scripts/get_alerts_index.sh index bfa74aa016f02e..addd2d4ab6195e 100755 --- a/x-pack/plugins/rule_registry/server/scripts/get_alerts_index.sh +++ b/x-pack/plugins/rule_registry/server/scripts/get_alerts_index.sh @@ -20,4 +20,4 @@ curl -v -k \ -u $USER:changeme \ -X GET "${KIBANA_URL}${SPACE_URL}/internal/rac/alerts/index" | jq . -# -X GET "${KIBANA_URL}${SPACE_URL}/api/apm/settings/apm-alerts-as-data-indices" | jq . +# -X GET "${KIBANA_URL}${SPACE_URL}/internal/apm/settings/apm-alerts-as-data-indices" | jq . diff --git a/x-pack/plugins/security/common/types.ts b/x-pack/plugins/security/common/types.ts index e6354841cc9e01..2d38dbdccb414d 100644 --- a/x-pack/plugins/security/common/types.ts +++ b/x-pack/plugins/security/common/types.ts @@ -19,3 +19,7 @@ export enum LogoutReason { 'LOGGED_OUT' = 'LOGGED_OUT', 'UNAUTHENTICATED' = 'UNAUTHENTICATED', } + +export interface SecurityCheckupState { + displayAlert: boolean; +} diff --git a/x-pack/plugins/security/kibana.json b/x-pack/plugins/security/kibana.json index a29c01b0f31ccd..2eeac40e22f141 100644 --- a/x-pack/plugins/security/kibana.json +++ b/x-pack/plugins/security/kibana.json @@ -8,8 +8,8 @@ "version": "8.0.0", "kibanaVersion": "kibana", "configPath": ["xpack", "security"], - "requiredPlugins": ["data", "features", "licensing", "taskManager", "securityOss"], - "optionalPlugins": ["home", "management", "usageCollection", "spaces"], + "requiredPlugins": ["data", "features", "licensing", "taskManager"], + "optionalPlugins": ["home", "management", "usageCollection", "spaces", "share"], "server": true, "ui": true, "requiredBundles": [ diff --git a/x-pack/plugins/security/public/anonymous_access/anonymous_access_service.ts b/x-pack/plugins/security/public/anonymous_access/anonymous_access_service.ts new file mode 100644 index 00000000000000..7f72fe9eaa0f17 --- /dev/null +++ b/x-pack/plugins/security/public/anonymous_access/anonymous_access_service.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Capabilities, HttpStart } from 'src/core/public'; + +import type { + AnonymousAccessServiceContract, + AnonymousAccessState, +} from '../../../../../src/plugins/share/common'; +import type { SharePluginSetup } from '../../../../../src/plugins/share/public'; + +const DEFAULT_ANONYMOUS_ACCESS_STATE = Object.freeze({ + isEnabled: false, + accessURLParameters: null, +}); + +interface SetupDeps { + share: Pick; +} + +interface StartDeps { + http: HttpStart; +} + +/** + * Service that allows to retrieve application state. + */ +export class AnonymousAccessService { + private internalService!: AnonymousAccessServiceContract; + + setup({ share }: SetupDeps) { + share.setAnonymousAccessServiceProvider(() => this.internalService); + } + + start({ http }: StartDeps) { + this.internalService = { + getCapabilities: () => + http.get('/internal/security/anonymous_access/capabilities'), + getState: () => + http.anonymousPaths.isAnonymous(window.location.pathname) + ? Promise.resolve(DEFAULT_ANONYMOUS_ACCESS_STATE) + : http + .get('/internal/security/anonymous_access/state') + .catch(() => DEFAULT_ANONYMOUS_ACCESS_STATE), + }; + } +} diff --git a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/constants.ts b/x-pack/plugins/security/public/anonymous_access/index.ts similarity index 61% rename from x-pack/plugins/spaces/public/share_saved_objects_to_space/components/constants.ts rename to x-pack/plugins/security/public/anonymous_access/index.ts index ef3248e1cd60a8..8cee89d1c13d2b 100644 --- a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/constants.ts +++ b/x-pack/plugins/security/public/anonymous_access/index.ts @@ -5,8 +5,4 @@ * 2.0. */ -import { i18n } from '@kbn/i18n'; - -export const DEFAULT_OBJECT_NOUN = i18n.translate('xpack.spaces.shareToSpace.objectNoun', { - defaultMessage: 'object', -}); +export { AnonymousAccessService } from './anonymous_access_service'; diff --git a/x-pack/plugins/security/public/config.ts b/x-pack/plugins/security/public/config.ts index 66dd4bab0a8504..a494efd02078cc 100644 --- a/x-pack/plugins/security/public/config.ts +++ b/x-pack/plugins/security/public/config.ts @@ -7,4 +7,5 @@ export interface ConfigType { loginAssistanceMessage: string; + showInsecureClusterWarning: boolean; } diff --git a/x-pack/plugins/security/public/mocks.ts b/x-pack/plugins/security/public/mocks.ts index b936f8d01cfd51..ac478ff0934dba 100644 --- a/x-pack/plugins/security/public/mocks.ts +++ b/x-pack/plugins/security/public/mocks.ts @@ -10,13 +10,11 @@ import type { MockAuthenticatedUserProps } from '../common/model/authenticated_u import { mockAuthenticatedUser } from '../common/model/authenticated_user.mock'; import { authenticationMock } from './authentication/index.mock'; import { navControlServiceMock } from './nav_control/index.mock'; -import { createSessionTimeoutMock } from './session/session_timeout.mock'; import { getUiApiMock } from './ui_api/index.mock'; function createSetupMock() { return { authc: authenticationMock.createSetup(), - sessionTimeout: createSessionTimeoutMock(), license: licenseMock.create(), }; } diff --git a/x-pack/plugins/security/public/plugin.test.tsx b/x-pack/plugins/security/public/plugin.test.tsx index 258b0ef9ec6f57..2bc4932b12a0b8 100644 --- a/x-pack/plugins/security/public/plugin.test.tsx +++ b/x-pack/plugins/security/public/plugin.test.tsx @@ -12,7 +12,6 @@ import type { CoreSetup } from 'src/core/public'; import { coreMock } from 'src/core/public/mocks'; import type { DataPublicPluginStart } from 'src/plugins/data/public'; import { managementPluginMock } from 'src/plugins/management/public/mocks'; -import { mockSecurityOssPlugin } from 'src/plugins/security_oss/public/mocks'; import type { FeaturesPluginStart } from '../../features/public'; import { licensingMock } from '../../licensing/public/mocks'; @@ -38,7 +37,6 @@ describe('Security Plugin', () => { }) as CoreSetup, { licensing: licensingMock.createSetup(), - securityOss: mockSecurityOssPlugin.createSetup(), } ) ).toEqual({ @@ -64,7 +62,6 @@ describe('Security Plugin', () => { plugin.setup(coreSetupMock as CoreSetup, { licensing: licensingMock.createSetup(), - securityOss: mockSecurityOssPlugin.createSetup(), management: managementSetupMock, }); @@ -90,12 +87,11 @@ describe('Security Plugin', () => { const plugin = new SecurityPlugin(coreMock.createPluginInitializerContext()); plugin.setup( coreMock.createSetup({ basePath: '/some-base-path' }) as CoreSetup, - { licensing: licensingMock.createSetup(), securityOss: mockSecurityOssPlugin.createSetup() } + { licensing: licensingMock.createSetup() } ); expect( plugin.start(coreMock.createStart({ basePath: '/some-base-path' }), { - securityOss: mockSecurityOssPlugin.createStart(), data: {} as DataPublicPluginStart, features: {} as FeaturesPluginStart, }) @@ -131,14 +127,12 @@ describe('Security Plugin', () => { coreMock.createSetup({ basePath: '/some-base-path' }) as CoreSetup, { licensing: licensingMock.createSetup(), - securityOss: mockSecurityOssPlugin.createSetup(), management: managementSetupMock, } ); const coreStart = coreMock.createStart({ basePath: '/some-base-path' }); plugin.start(coreStart, { - securityOss: mockSecurityOssPlugin.createStart(), data: {} as DataPublicPluginStart, features: {} as FeaturesPluginStart, management: managementStartMock, @@ -153,7 +147,7 @@ describe('Security Plugin', () => { const plugin = new SecurityPlugin(coreMock.createPluginInitializerContext()); plugin.setup( coreMock.createSetup({ basePath: '/some-base-path' }) as CoreSetup, - { licensing: licensingMock.createSetup(), securityOss: mockSecurityOssPlugin.createSetup() } + { licensing: licensingMock.createSetup() } ); expect(() => plugin.stop()).not.toThrow(); @@ -164,11 +158,10 @@ describe('Security Plugin', () => { plugin.setup( coreMock.createSetup({ basePath: '/some-base-path' }) as CoreSetup, - { licensing: licensingMock.createSetup(), securityOss: mockSecurityOssPlugin.createSetup() } + { licensing: licensingMock.createSetup() } ); plugin.start(coreMock.createStart({ basePath: '/some-base-path' }), { - securityOss: mockSecurityOssPlugin.createStart(), data: {} as DataPublicPluginStart, features: {} as FeaturesPluginStart, }); diff --git a/x-pack/plugins/security/public/plugin.tsx b/x-pack/plugins/security/public/plugin.tsx index 78144f0717164c..043cf0765ff31b 100644 --- a/x-pack/plugins/security/public/plugin.tsx +++ b/x-pack/plugins/security/public/plugin.tsx @@ -10,18 +10,16 @@ import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src import type { DataPublicPluginStart } from 'src/plugins/data/public'; import type { HomePublicPluginSetup } from 'src/plugins/home/public'; import type { ManagementSetup, ManagementStart } from 'src/plugins/management/public'; -import type { - SecurityOssPluginSetup, - SecurityOssPluginStart, -} from 'src/plugins/security_oss/public'; import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public'; +import type { SharePluginSetup, SharePluginStart } from '../../../../src/plugins/share/public'; import type { FeaturesPluginStart } from '../../features/public'; import type { LicensingPluginSetup } from '../../licensing/public'; import type { SpacesPluginStart } from '../../spaces/public'; import { SecurityLicenseService } from '../common/licensing'; import type { SecurityLicense } from '../common/licensing'; import { accountManagementApp } from './account_management'; +import { AnonymousAccessService } from './anonymous_access'; import type { AuthenticationServiceSetup, AuthenticationServiceStart } from './authentication'; import { AuthenticationService } from './authentication'; import type { ConfigType } from './config'; @@ -35,17 +33,17 @@ import { getUiApi } from './ui_api'; export interface PluginSetupDependencies { licensing: LicensingPluginSetup; - securityOss: SecurityOssPluginSetup; home?: HomePublicPluginSetup; management?: ManagementSetup; + share?: SharePluginSetup; } export interface PluginStartDependencies { data: DataPublicPluginStart; features: FeaturesPluginStart; - securityOss: SecurityOssPluginStart; management?: ManagementStart; spaces?: SpacesPluginStart; + share?: SharePluginStart; } export class SecurityPlugin @@ -57,22 +55,21 @@ export class SecurityPlugin PluginStartDependencies > { + private readonly config = this.initializerContext.config.get(); private sessionTimeout!: SessionTimeout; private readonly authenticationService = new AuthenticationService(); private readonly navControlService = new SecurityNavControlService(); private readonly securityLicenseService = new SecurityLicenseService(); private readonly managementService = new ManagementService(); - private readonly securityCheckupService = new SecurityCheckupService(); + private readonly securityCheckupService = new SecurityCheckupService(this.config, localStorage); + private readonly anonymousAccessService = new AnonymousAccessService(); private authc!: AuthenticationServiceSetup; - private readonly config: ConfigType; - constructor(private readonly initializerContext: PluginInitializerContext) { - this.config = this.initializerContext.config.get(); - } + constructor(private readonly initializerContext: PluginInitializerContext) {} public setup( core: CoreSetup, - { home, licensing, management, securityOss }: PluginSetupDependencies + { home, licensing, management, share }: PluginSetupDependencies ): SecurityPluginSetup { const { http, notifications } = core; const { anonymousPaths } = http; @@ -86,7 +83,7 @@ export class SecurityPlugin const { license } = this.securityLicenseService.setup({ license$: licensing.license$ }); - this.securityCheckupService.setup({ securityOssSetup: securityOss }); + this.securityCheckupService.setup({ http: core.http }); this.authc = this.authenticationService.setup({ application: core.application, @@ -135,6 +132,10 @@ export class SecurityPlugin }); } + if (share) { + this.anonymousAccessService.setup({ share }); + } + return { authc: this.authc, license, @@ -143,15 +144,23 @@ export class SecurityPlugin public start( core: CoreStart, - { management, securityOss }: PluginStartDependencies + { management, share }: PluginStartDependencies ): SecurityPluginStart { this.sessionTimeout.start(); - this.securityCheckupService.start({ securityOssStart: securityOss, docLinks: core.docLinks }); + this.securityCheckupService.start({ + http: core.http, + notifications: core.notifications, + docLinks: core.docLinks, + }); if (management) { this.managementService.start({ capabilities: core.application.capabilities }); } + if (share) { + this.anonymousAccessService.start({ http: core.http }); + } + return { uiApi: getUiApi({ core }), navControlService: this.navControlService.start({ core }), @@ -164,7 +173,6 @@ export class SecurityPlugin this.navControlService.stop(); this.securityLicenseService.stop(); this.managementService.stop(); - this.securityCheckupService.stop(); } } diff --git a/x-pack/plugins/security/public/security_checkup/components/insecure_cluster_alert.tsx b/x-pack/plugins/security/public/security_checkup/components/insecure_cluster_alert.tsx index eeeac4533ed12f..86ab93574211c7 100644 --- a/x-pack/plugins/security/public/security_checkup/components/insecure_cluster_alert.tsx +++ b/x-pack/plugins/security/public/security_checkup/components/insecure_cluster_alert.tsx @@ -26,15 +26,13 @@ export const insecureClusterAlertTitle = i18n.translate( ); export const insecureClusterAlertText = ( - getDocLinks: () => DocLinksStart, + docLinks: DocLinksStart, onDismiss: (persist: boolean) => void ) => ((e) => { const AlertText = () => { const [persist, setPersist] = useState(false); - const enableSecurityDocLink = `${ - getDocLinks().links.security.elasticsearchEnableSecurity - }?blade=kibanasecuritymessage`; + const enableSecurityDocLink = `${docLinks.links.security.elasticsearchEnableSecurity}?blade=kibanasecuritymessage`; return ( diff --git a/x-pack/plugins/security/public/security_checkup/security_checkup_service.test.ts b/x-pack/plugins/security/public/security_checkup/security_checkup_service.test.ts index c96b1e888ff9c3..1c4a15a8cfb933 100644 --- a/x-pack/plugins/security/public/security_checkup/security_checkup_service.test.ts +++ b/x-pack/plugins/security/public/security_checkup/security_checkup_service.test.ts @@ -5,75 +5,176 @@ * 2.0. */ -import type { MountPoint } from 'src/core/public'; -import { docLinksServiceMock } from 'src/core/public/mocks'; -import { mockSecurityOssPlugin } from 'src/plugins/security_oss/public/mocks'; +import { nextTick } from '@kbn/test/jest'; +import type { DocLinksStart } from 'src/core/public'; +import { coreMock } from 'src/core/public/mocks'; -import { insecureClusterAlertTitle } from './components'; +import type { ConfigType } from '../config'; import { SecurityCheckupService } from './security_checkup_service'; -let mockOnDismiss = jest.fn(); +let mockOnDismissCallback: (persist: boolean) => void = jest.fn().mockImplementation(() => { + throw new Error('expected callback to be replaced!'); +}); jest.mock('./components', () => { return { insecureClusterAlertTitle: 'mock insecure cluster title', - insecureClusterAlertText: (getDocLinksService: any, onDismiss: any) => { - mockOnDismiss = onDismiss; - const { insecureClusterAlertText } = jest.requireActual( - './components/insecure_cluster_alert' - ); - return insecureClusterAlertText(getDocLinksService, onDismiss); + insecureClusterAlertText: ( + _getDocLinks: () => DocLinksStart, + onDismiss: (persist: boolean) => void + ) => { + mockOnDismissCallback = onDismiss; + return 'mock insecure cluster text'; }, }; }); +interface TestParams { + showInsecureClusterWarning: boolean; + displayAlert: boolean; + tenant?: string; + storageValue?: string; +} + +async function setupAndStart({ + showInsecureClusterWarning, + displayAlert, + tenant = '/server-base-path', + storageValue, +}: TestParams) { + const coreSetup = coreMock.createSetup(); + (coreSetup.http.basePath.serverBasePath as string) = tenant; + + const coreStart = coreMock.createStart(); + coreStart.http.get.mockResolvedValue({ displayAlert }); + coreStart.notifications.toasts.addWarning.mockReturnValue({ id: 'mock_alert_id' }); + + const config = { showInsecureClusterWarning } as ConfigType; + const storage = coreMock.createStorage(); + if (storageValue) { + storage.getItem.mockReturnValue(storageValue); + } + + const service = new SecurityCheckupService(config, storage); + service.setup(coreSetup); + service.start(coreStart); + await nextTick(); + + return { coreSetup, coreStart, storage }; +} + describe('SecurityCheckupService', () => { - describe('#setup', () => { - it('configures the alert title and text for the default distribution', async () => { - const securityOssSetup = mockSecurityOssPlugin.createSetup(); - const service = new SecurityCheckupService(); - service.setup({ securityOssSetup }); - - expect(securityOssSetup.insecureCluster.setAlertTitle).toHaveBeenCalledWith( - insecureClusterAlertTitle - ); + describe('display scenarios', () => { + it('does not display an alert when the warning is explicitly disabled via config', async () => { + const testParams = { + showInsecureClusterWarning: false, + displayAlert: true, + }; + const { coreStart, storage } = await setupAndStart(testParams); - expect(securityOssSetup.insecureCluster.setAlertText).toHaveBeenCalledTimes(1); + expect(coreStart.http.get).not.toHaveBeenCalled(); + expect(coreStart.notifications.toasts.addWarning).not.toHaveBeenCalled(); + expect(coreStart.notifications.toasts.remove).not.toHaveBeenCalled(); + expect(storage.setItem).not.toHaveBeenCalled(); }); - }); - describe('#start', () => { - it('onDismiss triggers hiding of the alert', async () => { - const securityOssSetup = mockSecurityOssPlugin.createSetup(); - const securityOssStart = mockSecurityOssPlugin.createStart(); - const service = new SecurityCheckupService(); - service.setup({ securityOssSetup }); - service.start({ securityOssStart, docLinks: docLinksServiceMock.createStartContract() }); - expect(securityOssStart.insecureCluster.hideAlert).toHaveBeenCalledTimes(0); + it('does not display an alert when state indicates that alert should not be shown', async () => { + const testParams = { + showInsecureClusterWarning: true, + displayAlert: false, + }; + const { coreStart, storage } = await setupAndStart(testParams); - mockOnDismiss(); + expect(coreStart.http.get).toHaveBeenCalledTimes(1); + expect(coreStart.notifications.toasts.addWarning).not.toHaveBeenCalled(); + expect(coreStart.notifications.toasts.remove).not.toHaveBeenCalled(); + expect(storage.setItem).not.toHaveBeenCalled(); + }); - expect(securityOssStart.insecureCluster.hideAlert).toHaveBeenCalledTimes(1); + it('only reads storage information from the current tenant', async () => { + const testParams = { + showInsecureClusterWarning: true, + displayAlert: false, + tenant: '/my-specific-tenant', + storageValue: JSON.stringify({ show: false }), + }; + const { storage } = await setupAndStart(testParams); + + expect(storage.getItem).toHaveBeenCalledTimes(1); + expect(storage.getItem).toHaveBeenCalledWith( + 'insecureClusterWarningVisibility/my-specific-tenant' + ); + }); + + it('does not display an alert when hidden via storage', async () => { + const testParams = { + showInsecureClusterWarning: true, + displayAlert: true, + storageValue: JSON.stringify({ show: false }), + }; + const { coreStart, storage } = await setupAndStart(testParams); + + expect(coreStart.http.get).not.toHaveBeenCalled(); + expect(coreStart.notifications.toasts.addWarning).not.toHaveBeenCalled(); + expect(coreStart.notifications.toasts.remove).not.toHaveBeenCalled(); + expect(storage.setItem).not.toHaveBeenCalled(); }); - it('configures the doc link correctly', async () => { - const securityOssSetup = mockSecurityOssPlugin.createSetup(); - const securityOssStart = mockSecurityOssPlugin.createStart(); - const service = new SecurityCheckupService(); - service.setup({ securityOssSetup }); - service.start({ securityOssStart, docLinks: docLinksServiceMock.createStartContract() }); + it('displays an alert when persisted preference is corrupted', async () => { + const testParams = { + showInsecureClusterWarning: true, + displayAlert: true, + storageValue: '{ this is a string of invalid JSON', + }; + const { coreStart, storage } = await setupAndStart(testParams); - const [alertText] = securityOssSetup.insecureCluster.setAlertText.mock.calls[0]; + expect(coreStart.http.get).toHaveBeenCalledTimes(1); + expect(coreStart.notifications.toasts.addWarning).toHaveBeenCalledTimes(1); + expect(coreStart.notifications.toasts.remove).not.toHaveBeenCalled(); + expect(storage.setItem).not.toHaveBeenCalled(); + }); + + it('displays an alert when enabled via config and endpoint checks', async () => { + const testParams = { + showInsecureClusterWarning: true, + displayAlert: true, + }; + const { coreStart, storage } = await setupAndStart(testParams); + + expect(coreStart.http.get).toHaveBeenCalledTimes(1); + expect(coreStart.notifications.toasts.addWarning).toHaveBeenCalledTimes(1); + expect(coreStart.notifications.toasts.addWarning.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "iconType": "alert", + "text": "mock insecure cluster text", + "title": "mock insecure cluster title", + }, + Object { + "toastLifeTimeMs": 864000000, + }, + ] + `); + + expect(coreStart.notifications.toasts.remove).not.toHaveBeenCalled(); + expect(storage.setItem).not.toHaveBeenCalled(); + }); - const container = document.createElement('div'); - (alertText as MountPoint)(container); + it('dismisses the alert when requested, and remembers this preference', async () => { + const testParams = { + showInsecureClusterWarning: true, + displayAlert: true, + }; + const { coreStart, storage } = await setupAndStart(testParams); - const docLink = container - .querySelector('[data-test-subj="learnMoreButton"]') - ?.getAttribute('href'); + expect(coreStart.http.get).toHaveBeenCalledTimes(1); + expect(coreStart.notifications.toasts.addWarning).toHaveBeenCalledTimes(1); - expect(docLink).toMatchInlineSnapshot( - `"https://www.elastic.co/guide/en/elasticsearch/reference/mocked-test-branch/configuring-stack-security.html?blade=kibanasecuritymessage"` + mockOnDismissCallback(true); + expect(coreStart.notifications.toasts.remove).toHaveBeenCalledTimes(1); + expect(storage.setItem).toHaveBeenCalledWith( + 'insecureClusterWarningVisibility/server-base-path', + JSON.stringify({ show: false }) ); }); }); diff --git a/x-pack/plugins/security/public/security_checkup/security_checkup_service.tsx b/x-pack/plugins/security/public/security_checkup/security_checkup_service.tsx index 02adb85c21a808..4d2e92d2a50794 100644 --- a/x-pack/plugins/security/public/security_checkup/security_checkup_service.tsx +++ b/x-pack/plugins/security/public/security_checkup/security_checkup_service.tsx @@ -5,48 +5,128 @@ * 2.0. */ -import type { DocLinksStart } from 'src/core/public'; +import { BehaviorSubject, combineLatest, from } from 'rxjs'; +import { distinctUntilChanged, map } from 'rxjs/operators'; + import type { - SecurityOssPluginSetup, - SecurityOssPluginStart, -} from 'src/plugins/security_oss/public'; + DocLinksStart, + HttpSetup, + HttpStart, + NotificationsStart, + Toast, +} from 'src/core/public'; +import type { SecurityCheckupState } from '../../common/types'; +import type { ConfigType } from '../config'; import { insecureClusterAlertText, insecureClusterAlertTitle } from './components'; interface SetupDeps { - securityOssSetup: SecurityOssPluginSetup; + http: HttpSetup; } interface StartDeps { - securityOssStart: SecurityOssPluginStart; + http: HttpStart; + notifications: NotificationsStart; docLinks: DocLinksStart; } +const DEFAULT_SECURITY_CHECKUP_STATE = Object.freeze({ + displayAlert: false, +}); + export class SecurityCheckupService { - private securityOssStart?: SecurityOssPluginStart; + private enabled: boolean; + + private alertVisibility$: BehaviorSubject; + + private storage: Storage; + + private alertToast?: Toast; - private docLinks?: DocLinksStart; + private storageKey?: string; - public setup({ securityOssSetup }: SetupDeps) { - securityOssSetup.insecureCluster.setAlertTitle(insecureClusterAlertTitle); - securityOssSetup.insecureCluster.setAlertText( - insecureClusterAlertText( - () => this.docLinks!, - (persist: boolean) => this.onDismiss(persist) + constructor(config: Pick, storage: Storage) { + this.storage = storage; + this.enabled = config.showInsecureClusterWarning; + this.alertVisibility$ = new BehaviorSubject(this.enabled); + } + + public setup({ http }: SetupDeps) { + const tenant = http.basePath.serverBasePath; + this.storageKey = `insecureClusterWarningVisibility${tenant}`; + this.enabled = this.enabled && this.getPersistedVisibilityPreference(); + this.alertVisibility$.next(this.enabled); + } + + public start(startDeps: StartDeps) { + if (this.enabled) { + this.initializeAlert(startDeps); + } + } + + private initializeAlert({ http, notifications, docLinks }: StartDeps) { + const appState$ = from(this.getSecurityCheckupState(http)); + + // 10 days is reasonably long enough to call "forever" for a page load. + // Can't go too much longer than this. See https://github.com/elastic/kibana/issues/64264#issuecomment-618400354 + const oneMinute = 60000; + const tenDays = oneMinute * 60 * 24 * 10; + + combineLatest([appState$, this.alertVisibility$]) + .pipe( + map(([{ displayAlert }, isAlertVisible]) => displayAlert && isAlertVisible), + distinctUntilChanged() ) - ); + .subscribe((showAlert) => { + if (showAlert && !this.alertToast) { + this.alertToast = notifications.toasts.addWarning( + { + title: insecureClusterAlertTitle, + text: insecureClusterAlertText(docLinks, (persist: boolean) => + this.setAlertVisibility(false, persist) + ), + iconType: 'alert', + }, + { + toastLifeTimeMs: tenDays, + } + ); + } else if (!showAlert && this.alertToast) { + notifications.toasts.remove(this.alertToast); + this.alertToast = undefined; + } + }); } - public start({ securityOssStart, docLinks }: StartDeps) { - this.securityOssStart = securityOssStart; - this.docLinks = docLinks; + private getSecurityCheckupState(http: HttpStart) { + return http.anonymousPaths.isAnonymous(window.location.pathname) + ? Promise.resolve(DEFAULT_SECURITY_CHECKUP_STATE) + : http + .get('/internal/security/security_checkup/state') + .catch(() => DEFAULT_SECURITY_CHECKUP_STATE); } - private onDismiss(persist: boolean) { - if (this.securityOssStart) { - this.securityOssStart.insecureCluster.hideAlert(persist); + private setAlertVisibility(show: boolean, persist: boolean) { + if (!this.enabled) { + return; + } + this.alertVisibility$.next(show); + if (persist) { + this.setPersistedVisibilityPreference(show); } } - public stop() {} + private getPersistedVisibilityPreference() { + const entry = this.storage.getItem(this.storageKey!) ?? '{}'; + try { + const { show = true } = JSON.parse(entry); + return show; + } catch (e) { + return true; + } + } + + private setPersistedVisibilityPreference(show: boolean) { + this.storage.setItem(this.storageKey!, JSON.stringify({ show })); + } } diff --git a/x-pack/plugins/security/public/session/session_timeout.mock.ts b/x-pack/plugins/security/public/session/session_timeout.mock.ts deleted file mode 100644 index 15071b08ded8f1..00000000000000 --- a/x-pack/plugins/security/public/session/session_timeout.mock.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 type { PublicMethodsOf } from '@kbn/utility-types'; - -import type { SessionTimeout } from './session_timeout'; - -export function createSessionTimeoutMock() { - return { - start: jest.fn(), - stop: jest.fn(), - } as jest.Mocked>; -} diff --git a/x-pack/plugins/security/server/config.test.ts b/x-pack/plugins/security/server/config.test.ts index 98f11d56853b2f..4a7d8c7961cf55 100644 --- a/x-pack/plugins/security/server/config.test.ts +++ b/x-pack/plugins/security/server/config.test.ts @@ -65,6 +65,7 @@ describe('config schema', () => { "idleTimeout": "PT1H", "lifespan": "P30D", }, + "showInsecureClusterWarning": true, } `); @@ -117,6 +118,7 @@ describe('config schema', () => { "idleTimeout": "PT1H", "lifespan": "P30D", }, + "showInsecureClusterWarning": true, } `); @@ -168,6 +170,7 @@ describe('config schema', () => { "idleTimeout": "PT1H", "lifespan": "P30D", }, + "showInsecureClusterWarning": true, } `); }); diff --git a/x-pack/plugins/security/server/config.ts b/x-pack/plugins/security/server/config.ts index af5703cff158cb..07ff81e092f5f1 100644 --- a/x-pack/plugins/security/server/config.ts +++ b/x-pack/plugins/security/server/config.ts @@ -200,6 +200,7 @@ const providersConfigSchema = schema.object( export const ConfigSchema = schema.object({ enabled: schema.boolean({ defaultValue: true }), loginAssistanceMessage: schema.string({ defaultValue: '' }), + showInsecureClusterWarning: schema.boolean({ defaultValue: true }), loginHelp: schema.maybe(schema.string()), cookieName: schema.string({ defaultValue: 'sid' }), encryptionKey: schema.conditional( diff --git a/x-pack/plugins/security/server/config_deprecations.test.ts b/x-pack/plugins/security/server/config_deprecations.test.ts index beac88293026c1..d9db18cdb96afe 100644 --- a/x-pack/plugins/security/server/config_deprecations.test.ts +++ b/x-pack/plugins/security/server/config_deprecations.test.ts @@ -171,6 +171,22 @@ describe('Config Deprecations', () => { `); }); + it('renames security.showInsecureClusterWarning to xpack.security.showInsecureClusterWarning', () => { + const config = { + security: { + showInsecureClusterWarning: false, + }, + }; + const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + expect(migrated.security.showInsecureClusterWarning).not.toBeDefined(); + expect(migrated.xpack.security.showInsecureClusterWarning).toEqual(false); + expect(messages).toMatchInlineSnapshot(` + Array [ + "Setting \\"security.showInsecureClusterWarning\\" has been replaced by \\"xpack.security.showInsecureClusterWarning\\"", + ] + `); + }); + it('warns when using the legacy audit logger', () => { const config = { xpack: { diff --git a/x-pack/plugins/security/server/config_deprecations.ts b/x-pack/plugins/security/server/config_deprecations.ts index 169211184a3256..dbe708eab51a2f 100644 --- a/x-pack/plugins/security/server/config_deprecations.ts +++ b/x-pack/plugins/security/server/config_deprecations.ts @@ -10,6 +10,7 @@ import type { ConfigDeprecationProvider } from 'src/core/server'; export const securityConfigDeprecationProvider: ConfigDeprecationProvider = ({ rename, + renameFromRoot, unused, }) => [ rename('sessionTimeout', 'session.idleTimeout'), @@ -21,10 +22,15 @@ export const securityConfigDeprecationProvider: ConfigDeprecationProvider = ({ rename('audit.appender.strategy.kind', 'audit.appender.strategy.type'), rename('audit.appender.path', 'audit.appender.fileName'), + renameFromRoot( + 'security.showInsecureClusterWarning', + 'xpack.security.showInsecureClusterWarning' + ), + unused('authorization.legacyFallback.enabled'), unused('authc.saml.maxRedirectURLSize'), // Deprecation warning for the legacy audit logger. - (settings, fromPath, addDeprecation) => { + (settings, fromPath, addDeprecation, { branch }) => { const auditLoggingEnabled = settings?.xpack?.security?.audit?.enabled ?? false; const legacyAuditLoggerEnabled = !settings?.xpack?.security?.audit?.appender; if (auditLoggingEnabled && legacyAuditLoggerEnabled) { @@ -36,8 +42,7 @@ export const securityConfigDeprecationProvider: ConfigDeprecationProvider = ({ defaultMessage: 'The legacy audit logger is deprecated in favor of the new ECS-compliant audit logger.', }), - documentationUrl: - 'https://www.elastic.co/guide/en/kibana/current/security-settings-kb.html#audit-logging-settings', + documentationUrl: `https://www.elastic.co/guide/en/kibana/${branch}/security-settings-kb.html#audit-logging-settings`, correctiveActions: { manualSteps: [ i18n.translate('xpack.security.deprecations.auditLogger.manualStepOneMessage', { diff --git a/x-pack/plugins/security/server/index.ts b/x-pack/plugins/security/server/index.ts index a48c6833096ccb..b3bc85676b07ad 100644 --- a/x-pack/plugins/security/server/index.ts +++ b/x-pack/plugins/security/server/index.ts @@ -40,6 +40,7 @@ export const config: PluginConfigDescriptor> = { deprecations: securityConfigDeprecationProvider, exposeToBrowser: { loginAssistanceMessage: true, + showInsecureClusterWarning: true, }, }; export const plugin: PluginInitializer< diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts index 2ad75a1c531744..98e77038f168ab 100644 --- a/x-pack/plugins/security/server/plugin.ts +++ b/x-pack/plugins/security/server/plugin.ts @@ -18,7 +18,6 @@ import type { Plugin, PluginInitializerContext, } from 'src/core/server'; -import type { SecurityOssPluginSetup } from 'src/plugins/security_oss/server'; import type { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import type { @@ -111,7 +110,6 @@ export interface PluginSetupDependencies { licensing: LicensingPluginSetup; taskManager: TaskManagerSetupContract; usageCollection?: UsageCollectionSetup; - securityOss?: SecurityOssPluginSetup; spaces?: SpacesPluginSetup; } @@ -131,7 +129,6 @@ export class SecurityPlugin private readonly logger: Logger; private authorizationSetup?: AuthorizationServiceSetupInternal; private auditSetup?: AuditServiceSetup; - private anonymousAccessStart?: AnonymousAccessServiceStart; private configSubscription?: Subscription; private config?: ConfigType; @@ -191,6 +188,13 @@ export class SecurityPlugin this.initializerContext.logger.get('anonymous-access'), this.getConfig ); + private anonymousAccessStart?: AnonymousAccessServiceStart; + private readonly getAnonymousAccess = () => { + if (!this.anonymousAccessStart) { + throw new Error(`anonymousAccessStart is not registered!`); + } + return this.anonymousAccessStart; + }; constructor(private readonly initializerContext: PluginInitializerContext) { this.logger = this.initializerContext.logger.get(); @@ -198,23 +202,17 @@ export class SecurityPlugin public setup( core: CoreSetup, - { - features, - licensing, - taskManager, - usageCollection, - securityOss, - spaces, - }: PluginSetupDependencies + { features, licensing, taskManager, usageCollection, spaces }: PluginSetupDependencies ) { + const config$ = this.initializerContext.config.create>().pipe( + map((rawConfig) => + createConfig(rawConfig, this.initializerContext.logger.get('config'), { + isTLSEnabled: core.http.getServerInfo().protocol === 'https', + }) + ) + ); this.configSubscription = combineLatest([ - this.initializerContext.config.create>().pipe( - map((rawConfig) => - createConfig(rawConfig, this.initializerContext.logger.get('config'), { - isTLSEnabled: core.http.getServerInfo().protocol === 'https', - }) - ) - ), + config$, this.initializerContext.config.legacy.globalConfig$, ]).subscribe(([config, { kibana }]) => { this.config = config; @@ -234,20 +232,6 @@ export class SecurityPlugin license$: licensing.license$, }); - if (securityOss) { - license.features$.subscribe(({ allowRbac }) => { - const showInsecureClusterWarning = !allowRbac; - securityOss.showInsecureClusterWarning$.next(showInsecureClusterWarning); - }); - - securityOss.setAnonymousAccessServiceProvider(() => { - if (!this.anonymousAccessStart) { - throw new Error('AnonymousAccess service is not started!'); - } - return this.anonymousAccessStart; - }); - } - securityFeatures.forEach((securityFeature) => features.registerElasticsearchFeature(securityFeature) ); @@ -312,6 +296,7 @@ export class SecurityPlugin httpResources: core.http.resources, logger: this.initializerContext.logger.get('routes'), config, + config$, authz: this.authorizationSetup, license, getSession: this.getSession, @@ -319,6 +304,7 @@ export class SecurityPlugin startServicesPromise.then((services) => services.features.getKibanaFeatures()), getFeatureUsageService: this.getFeatureUsageService, getAuthenticationService: this.getAuthentication, + getAnonymousAccessService: this.getAnonymousAccess, }); return Object.freeze({ diff --git a/x-pack/plugins/security/server/routes/anonymous_access/get_capabilities.test.ts b/x-pack/plugins/security/server/routes/anonymous_access/get_capabilities.test.ts new file mode 100644 index 00000000000000..d840351ea7dc66 --- /dev/null +++ b/x-pack/plugins/security/server/routes/anonymous_access/get_capabilities.test.ts @@ -0,0 +1,48 @@ +/* + * 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 { kibanaResponseFactory } from 'src/core/server'; +import { httpServerMock } from 'src/core/server/mocks'; + +import { routeDefinitionParamsMock, securityRequestHandlerContextMock } from '../index.mock'; +import { defineAnonymousAccessGetCapabilitiesRoutes } from './get_capabilities'; + +describe('GET /internal/security/anonymous_access/capabilities', () => { + it('returns anonymous access state', async () => { + const mockRouteDefinitionParams = routeDefinitionParamsMock.create(); + mockRouteDefinitionParams.getAnonymousAccessService.mockReturnValue({ + isAnonymousAccessEnabled: true, + accessURLParameters: new Map([['auth_provider_hint', 'anonymous1']]), + getCapabilities: jest.fn().mockResolvedValue({ + navLinks: {}, + management: {}, + catalogue: {}, + custom: { something: true }, + }), + }); + const mockContext = securityRequestHandlerContextMock.create(); + + defineAnonymousAccessGetCapabilitiesRoutes(mockRouteDefinitionParams); + + const [[, handler]] = mockRouteDefinitionParams.router.get.mock.calls; + + const headers = { authorization: 'foo' }; + const mockRequest = httpServerMock.createKibanaRequest({ + method: 'get', + path: `/internal/security/anonymous_access/capabilities`, + headers, + }); + const response = await handler(mockContext, mockRequest, kibanaResponseFactory); + expect(response.status).toBe(200); + expect(response.payload).toEqual({ + navLinks: {}, + management: {}, + catalogue: {}, + custom: { something: true }, + }); + }); +}); diff --git a/x-pack/plugins/security/server/routes/anonymous_access/get_capabilities.ts b/x-pack/plugins/security/server/routes/anonymous_access/get_capabilities.ts new file mode 100644 index 00000000000000..2a2f495cf062f6 --- /dev/null +++ b/x-pack/plugins/security/server/routes/anonymous_access/get_capabilities.ts @@ -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 type { RouteDefinitionParams } from '../'; + +/** + * Defines route that returns capabilities of the anonymous service account. + */ +export function defineAnonymousAccessGetCapabilitiesRoutes({ + router, + getAnonymousAccessService, +}: RouteDefinitionParams) { + router.get( + { path: '/internal/security/anonymous_access/capabilities', validate: false }, + async (_context, request, response) => { + const anonymousAccessService = getAnonymousAccessService(); + return response.ok({ body: await anonymousAccessService.getCapabilities(request) }); + } + ); +} diff --git a/x-pack/plugins/security/server/routes/anonymous_access/get_state.test.ts b/x-pack/plugins/security/server/routes/anonymous_access/get_state.test.ts new file mode 100644 index 00000000000000..80dbf5cada9eed --- /dev/null +++ b/x-pack/plugins/security/server/routes/anonymous_access/get_state.test.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { kibanaResponseFactory } from 'src/core/server'; +import { httpServerMock } from 'src/core/server/mocks'; + +import type { AnonymousAccessServiceStart } from '../../anonymous_access'; +import { routeDefinitionParamsMock, securityRequestHandlerContextMock } from '../index.mock'; +import { defineAnonymousAccessGetStateRoutes } from './get_state'; + +describe('GET /internal/security/anonymous_access/state', () => { + function doMockAndTest(accessURLParameters: AnonymousAccessServiceStart['accessURLParameters']) { + const mockRouteDefinitionParams = routeDefinitionParamsMock.create(); + mockRouteDefinitionParams.getAnonymousAccessService.mockReturnValue({ + isAnonymousAccessEnabled: true, + accessURLParameters, + getCapabilities: jest.fn(), + }); + const mockContext = securityRequestHandlerContextMock.create(); + + defineAnonymousAccessGetStateRoutes(mockRouteDefinitionParams); + + const [[, handler]] = mockRouteDefinitionParams.router.get.mock.calls; + + const headers = { authorization: 'foo' }; + const mockRequest = httpServerMock.createKibanaRequest({ + method: 'get', + path: `/internal/security/anonymous_access/state`, + headers, + }); + return handler(mockContext, mockRequest, kibanaResponseFactory); + } + + it('returns anonymous access state (with access URL parameters)', async () => { + const response = await doMockAndTest(new Map([['auth_provider_hint', 'anonymous1']])); + expect(response.status).toBe(200); + expect(response.payload).toEqual({ + isEnabled: true, + accessURLParameters: { auth_provider_hint: 'anonymous1' }, + }); + }); + + it('returns anonymous access state (without access URL parameters)', async () => { + const response = await doMockAndTest(null); + expect(response.status).toBe(200); + expect(response.payload).toEqual({ + isEnabled: true, + accessURLParameters: null, + }); + }); +}); diff --git a/x-pack/plugins/security/server/routes/anonymous_access/get_state.ts b/x-pack/plugins/security/server/routes/anonymous_access/get_state.ts new file mode 100644 index 00000000000000..f817ade1a10fd4 --- /dev/null +++ b/x-pack/plugins/security/server/routes/anonymous_access/get_state.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RouteDefinitionParams } from '..'; +import type { AnonymousAccessState } from '../../../../../../src/plugins/share/common'; + +/** + * Defines route that returns the state of anonymous access -- whether anonymous access is enabled, and what additional parameters should be + * added to the URL (if any). + */ +export function defineAnonymousAccessGetStateRoutes({ + router, + getAnonymousAccessService, +}: RouteDefinitionParams) { + router.get( + { path: '/internal/security/anonymous_access/state', validate: false }, + async (_context, _request, response) => { + const anonymousAccessService = getAnonymousAccessService(); + const accessURLParameters = anonymousAccessService.accessURLParameters + ? Object.fromEntries(anonymousAccessService.accessURLParameters.entries()) + : null; + const responseBody: AnonymousAccessState = { + isEnabled: anonymousAccessService.isAnonymousAccessEnabled, + accessURLParameters, + }; + return response.ok({ body: responseBody }); + } + ); +} diff --git a/x-pack/plugins/security/server/routes/anonymous_access/index.ts b/x-pack/plugins/security/server/routes/anonymous_access/index.ts new file mode 100644 index 00000000000000..53ed33e8741dbe --- /dev/null +++ b/x-pack/plugins/security/server/routes/anonymous_access/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RouteDefinitionParams } from '../'; +import { defineAnonymousAccessGetCapabilitiesRoutes } from './get_capabilities'; +import { defineAnonymousAccessGetStateRoutes } from './get_state'; + +export function defineAnonymousAccessRoutes(params: RouteDefinitionParams) { + defineAnonymousAccessGetCapabilitiesRoutes(params); + defineAnonymousAccessGetStateRoutes(params); +} diff --git a/x-pack/plugins/security/server/routes/index.mock.ts b/x-pack/plugins/security/server/routes/index.mock.ts index a92884c1dab75e..9b6e7948838c8d 100644 --- a/x-pack/plugins/security/server/routes/index.mock.ts +++ b/x-pack/plugins/security/server/routes/index.mock.ts @@ -5,26 +5,39 @@ * 2.0. */ +import { BehaviorSubject } from 'rxjs'; + import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import { httpResourcesMock, httpServiceMock, loggingSystemMock } from 'src/core/server/mocks'; +import { + coreMock, + httpResourcesMock, + httpServiceMock, + loggingSystemMock, +} from 'src/core/server/mocks'; +import { licensingMock } from '../../../licensing/server/mocks'; import { licenseMock } from '../../common/licensing/index.mock'; import { authenticationServiceMock } from '../authentication/authentication_service.mock'; import { authorizationMock } from '../authorization/index.mock'; import { ConfigSchema, createConfig } from '../config'; import { sessionMock } from '../session_management/session.mock'; +import type { SecurityRequestHandlerContext } from '../types'; import type { RouteDefinitionParams } from './'; export const routeDefinitionParamsMock = { - create: (config: Record = {}) => - ({ + create: (rawConfig: Record = {}) => { + const config = createConfig( + ConfigSchema.validate(rawConfig), + loggingSystemMock.create().get(), + { isTLSEnabled: false } + ); + return { router: httpServiceMock.createRouter(), basePath: httpServiceMock.createBasePath(), csp: httpServiceMock.createSetupContract().csp, logger: loggingSystemMock.create().get(), - config: createConfig(ConfigSchema.validate(config), loggingSystemMock.create().get(), { - isTLSEnabled: false, - }), + config, + config$: new BehaviorSubject(config).asObservable(), authz: authorizationMock.create(), license: licenseMock.create(), httpResources: httpResourcesMock.createRegistrar(), @@ -32,5 +45,14 @@ export const routeDefinitionParamsMock = { getFeatureUsageService: jest.fn(), getSession: jest.fn().mockReturnValue(sessionMock.create()), getAuthenticationService: jest.fn().mockReturnValue(authenticationServiceMock.createStart()), - } as unknown as DeeplyMockedKeys), + getAnonymousAccessService: jest.fn(), + } as unknown as DeeplyMockedKeys; + }, +}; + +export const securityRequestHandlerContextMock = { + create: (): SecurityRequestHandlerContext => ({ + core: coreMock.createRequestHandlerContext(), + licensing: licensingMock.createRequestHandlerContext(), + }), }; diff --git a/x-pack/plugins/security/server/routes/index.ts b/x-pack/plugins/security/server/routes/index.ts index 7a4310da3e4c7c..851e70a357cf9b 100644 --- a/x-pack/plugins/security/server/routes/index.ts +++ b/x-pack/plugins/security/server/routes/index.ts @@ -5,22 +5,27 @@ * 2.0. */ +import type { Observable } from 'rxjs'; + import type { PublicMethodsOf } from '@kbn/utility-types'; import type { HttpResources, IBasePath, Logger } from 'src/core/server'; import type { KibanaFeature } from '../../../features/server'; import type { SecurityLicense } from '../../common/licensing'; +import type { AnonymousAccessServiceStart } from '../anonymous_access'; import type { InternalAuthenticationServiceStart } from '../authentication'; import type { AuthorizationServiceSetupInternal } from '../authorization'; import type { ConfigType } from '../config'; import type { SecurityFeatureUsageServiceStart } from '../feature_usage'; import type { Session } from '../session_management'; import type { SecurityRouter } from '../types'; +import { defineAnonymousAccessRoutes } from './anonymous_access'; import { defineApiKeysRoutes } from './api_keys'; import { defineAuthenticationRoutes } from './authentication'; import { defineAuthorizationRoutes } from './authorization'; import { defineIndicesRoutes } from './indices'; import { defineRoleMappingRoutes } from './role_mapping'; +import { defineSecurityCheckupGetStateRoutes } from './security_checkup'; import { defineSessionManagementRoutes } from './session_management'; import { defineUsersRoutes } from './users'; import { defineViewRoutes } from './views'; @@ -34,12 +39,14 @@ export interface RouteDefinitionParams { httpResources: HttpResources; logger: Logger; config: ConfigType; + config$: Observable; authz: AuthorizationServiceSetupInternal; getSession: () => PublicMethodsOf; license: SecurityLicense; getFeatures: () => Promise; getFeatureUsageService: () => SecurityFeatureUsageServiceStart; getAuthenticationService: () => InternalAuthenticationServiceStart; + getAnonymousAccessService: () => AnonymousAccessServiceStart; } export function defineRoutes(params: RouteDefinitionParams) { @@ -51,4 +58,6 @@ export function defineRoutes(params: RouteDefinitionParams) { defineUsersRoutes(params); defineRoleMappingRoutes(params); defineViewRoutes(params); + defineAnonymousAccessRoutes(params); + defineSecurityCheckupGetStateRoutes(params); } diff --git a/x-pack/plugins/security/server/routes/security_checkup/get_state.test.mock.ts b/x-pack/plugins/security/server/routes/security_checkup/get_state.test.mock.ts new file mode 100644 index 00000000000000..57e1a20be966a8 --- /dev/null +++ b/x-pack/plugins/security/server/routes/security_checkup/get_state.test.mock.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { createClusterDataCheck } from '../../security_checkup'; + +export const mockCreateClusterDataCheck = jest.fn() as jest.MockedFunction< + typeof createClusterDataCheck +>; + +jest.mock('../../security_checkup', () => ({ + createClusterDataCheck: mockCreateClusterDataCheck, +})); diff --git a/x-pack/plugins/security/server/routes/security_checkup/get_state.test.ts b/x-pack/plugins/security/server/routes/security_checkup/get_state.test.ts new file mode 100644 index 00000000000000..9986c1e979b8b8 --- /dev/null +++ b/x-pack/plugins/security/server/routes/security_checkup/get_state.test.ts @@ -0,0 +1,140 @@ +/* + * 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. + */ + +// eslint-disable-next-line import/order +import { mockCreateClusterDataCheck } from './get_state.test.mock'; + +import type { Observable } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; + +import { kibanaResponseFactory } from 'src/core/server'; +import { httpServerMock } from 'src/core/server/mocks'; + +import type { SecurityLicenseFeatures } from '../../../common/licensing'; +import { licenseMock } from '../../../common/licensing/index.mock'; +import { routeDefinitionParamsMock, securityRequestHandlerContextMock } from '../index.mock'; +import { defineSecurityCheckupGetStateRoutes } from './get_state'; + +interface SetupParams { + showInsecureClusterWarning: boolean; + allowRbac: boolean; + doesClusterHaveUserData: boolean; +} + +function setup({ showInsecureClusterWarning, allowRbac, doesClusterHaveUserData }: SetupParams) { + const mockRouteDefinitionParams = routeDefinitionParamsMock.create(); + const configSubject = new BehaviorSubject({ showInsecureClusterWarning }); + (mockRouteDefinitionParams.config$ as Observable<{ showInsecureClusterWarning: boolean }>) = + configSubject.asObservable(); + + const licenseWithFeatures = licenseMock.create(); + const featuresSubject = new BehaviorSubject({ allowRbac } as SecurityLicenseFeatures); + licenseWithFeatures.features$ = featuresSubject.asObservable(); + + const mockClusterDataCheck = jest.fn().mockResolvedValue(doesClusterHaveUserData); + mockCreateClusterDataCheck.mockReturnValue(mockClusterDataCheck); + + const mockContext = securityRequestHandlerContextMock.create(); + defineSecurityCheckupGetStateRoutes({ + ...mockRouteDefinitionParams, + license: licenseWithFeatures, + }); + const [[, handler]] = mockRouteDefinitionParams.router.get.mock.calls; + const headers = { authorization: 'foo' }; + const mockRequest = httpServerMock.createKibanaRequest({ + method: 'get', + path: `/internal/security/anonymous_access/state`, + headers, + }); + + return { + configSubject, + featuresSubject, + mockClusterDataCheck, + simulateRequest: () => handler(mockContext, mockRequest, kibanaResponseFactory), + }; +} + +describe('GET /internal/security/security_checkup/state', () => { + it('responds `displayAlert == false` if plugin is not configured to display alerts', async () => { + const { simulateRequest, mockClusterDataCheck } = setup({ + showInsecureClusterWarning: false, + allowRbac: false, + doesClusterHaveUserData: true, + }); + + const response = await simulateRequest(); + expect(response.status).toBe(200); + expect(response.payload).toEqual({ displayAlert: false }); + expect(mockClusterDataCheck).not.toHaveBeenCalled(); + }); + + it('responds `displayAlert == false` if Elasticsearch security is already enabled', async () => { + const { simulateRequest, mockClusterDataCheck } = setup({ + showInsecureClusterWarning: true, + allowRbac: true, + doesClusterHaveUserData: true, + }); + + const response = await simulateRequest(); + expect(response.status).toBe(200); + expect(response.payload).toEqual({ displayAlert: false }); + expect(mockClusterDataCheck).not.toHaveBeenCalled(); + }); + + it('responds `displayAlert == false` if the cluster does not contain user data', async () => { + const { simulateRequest, mockClusterDataCheck } = setup({ + showInsecureClusterWarning: true, + allowRbac: false, + doesClusterHaveUserData: false, + }); + + const response = await simulateRequest(); + expect(response.status).toBe(200); + expect(response.payload).toEqual({ displayAlert: false }); + // since the plugin is configured to display alerts AND Elasticsearch security is disabled, we checked the cluster to see if it contained user data + expect(mockClusterDataCheck).toHaveBeenCalledTimes(1); + }); + + it('responds `displayAlert == true` if all conditions are met', async () => { + const { simulateRequest, mockClusterDataCheck } = setup({ + showInsecureClusterWarning: true, + allowRbac: false, + doesClusterHaveUserData: true, + }); + + const response = await simulateRequest(); + expect(response.status).toBe(200); + expect(response.payload).toEqual({ displayAlert: true }); + expect(mockClusterDataCheck).toHaveBeenCalledTimes(1); + }); + + it('handles state changes', async () => { + const { configSubject, featuresSubject, simulateRequest, mockClusterDataCheck } = setup({ + showInsecureClusterWarning: false, + allowRbac: false, + doesClusterHaveUserData: true, + }); + + const response1 = await simulateRequest(); + expect(response1.status).toBe(200); + expect(response1.payload).toEqual({ displayAlert: false }); + expect(mockClusterDataCheck).not.toHaveBeenCalled(); + + configSubject.next({ showInsecureClusterWarning: true }); // enable insecure cluster warning + const response2 = await simulateRequest(); + expect(response2.status).toBe(200); + expect(response2.payload).toEqual({ displayAlert: true }); // now that the warning is enabled, all conditions are met and it should be displayed + expect(mockClusterDataCheck).toHaveBeenCalledTimes(1); + + featuresSubject.next({ allowRbac: true } as SecurityLicenseFeatures); // enable Elasticsearch security + const response3 = await simulateRequest(); + expect(response3.status).toBe(200); + expect(response3.payload).toEqual({ displayAlert: false }); // now that Elasticsearch security is enabled, we don't need to display the alert anymore + expect(mockClusterDataCheck).toHaveBeenCalledTimes(1); // we did not check the cluster for data again because Elasticsearch security is enabled + }); +}); diff --git a/x-pack/plugins/security/server/routes/security_checkup/get_state.ts b/x-pack/plugins/security/server/routes/security_checkup/get_state.ts new file mode 100644 index 00000000000000..8c4e69cb87c814 --- /dev/null +++ b/x-pack/plugins/security/server/routes/security_checkup/get_state.ts @@ -0,0 +1,48 @@ +/* + * 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 { combineLatest } from 'rxjs'; + +import type { RouteDefinitionParams } from '..'; +import type { SecurityCheckupState } from '../../../common/types'; +import { createClusterDataCheck } from '../../security_checkup'; + +/** + * Defines route that returns the state of the security checkup feature. + */ +export function defineSecurityCheckupGetStateRoutes({ + router, + logger, + config$, + license, +}: RouteDefinitionParams) { + let showInsecureClusterWarning = false; + + combineLatest([config$, license.features$]).subscribe(([config, { allowRbac }]) => { + showInsecureClusterWarning = config.showInsecureClusterWarning && !allowRbac; + }); + + const doesClusterHaveUserData = createClusterDataCheck(); + + router.get( + { path: '/internal/security/security_checkup/state', validate: false }, + async (context, _request, response) => { + let displayAlert = false; + if (showInsecureClusterWarning) { + displayAlert = await doesClusterHaveUserData( + context.core.elasticsearch.client.asInternalUser, + logger + ); + } + + const state: SecurityCheckupState = { + displayAlert, + }; + return response.ok({ body: state }); + } + ); +} diff --git a/x-pack/plugins/spaces/public/lib/index.ts b/x-pack/plugins/security/server/routes/security_checkup/index.ts similarity index 80% rename from x-pack/plugins/spaces/public/lib/index.ts rename to x-pack/plugins/security/server/routes/security_checkup/index.ts index 8ba38e2ecefdd5..ff479dd16c6713 100644 --- a/x-pack/plugins/spaces/public/lib/index.ts +++ b/x-pack/plugins/security/server/routes/security_checkup/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { DocumentationLinksService } from './documentation_links'; +export { defineSecurityCheckupGetStateRoutes } from './get_state'; diff --git a/src/plugins/security_oss/server/check_cluster_data.test.ts b/x-pack/plugins/security/server/security_checkup/check_cluster_data.test.ts similarity index 95% rename from src/plugins/security_oss/server/check_cluster_data.test.ts rename to x-pack/plugins/security/server/security_checkup/check_cluster_data.test.ts index 6aa1cc9a28c39e..396e06bd1d04ee 100644 --- a/src/plugins/security_oss/server/check_cluster_data.test.ts +++ b/x-pack/plugins/security/server/security_checkup/check_cluster_data.test.ts @@ -1,9 +1,8 @@ /* * 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. + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import { elasticsearchServiceMock, loggingSystemMock } from 'src/core/server/mocks'; diff --git a/src/plugins/security_oss/server/check_cluster_data.ts b/x-pack/plugins/security/server/security_checkup/check_cluster_data.ts similarity index 84% rename from src/plugins/security_oss/server/check_cluster_data.ts rename to x-pack/plugins/security/server/security_checkup/check_cluster_data.ts index 19a4145333dd0c..bec8adfdc4f6b1 100644 --- a/src/plugins/security_oss/server/check_cluster_data.ts +++ b/x-pack/plugins/security/server/security_checkup/check_cluster_data.ts @@ -1,9 +1,8 @@ /* * 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. + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import type { ElasticsearchClient, Logger } from 'src/core/server'; diff --git a/x-pack/plugins/spaces/public/share_saved_objects_to_space/utils/index.ts b/x-pack/plugins/security/server/security_checkup/index.ts similarity index 79% rename from x-pack/plugins/spaces/public/share_saved_objects_to_space/utils/index.ts rename to x-pack/plugins/security/server/security_checkup/index.ts index a40bc87cd4dc30..fa4b5f67f85117 100644 --- a/x-pack/plugins/spaces/public/share_saved_objects_to_space/utils/index.ts +++ b/x-pack/plugins/security/server/security_checkup/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { createRedirectLegacyUrl } from './redirect_legacy_url'; +export { createClusterDataCheck } from './check_cluster_data'; diff --git a/x-pack/plugins/security/tsconfig.json b/x-pack/plugins/security/tsconfig.json index ea03b9dbb6471d..5cc25bbb440550 100644 --- a/x-pack/plugins/security/tsconfig.json +++ b/x-pack/plugins/security/tsconfig.json @@ -17,7 +17,7 @@ { "path": "../../../src/plugins/home/tsconfig.json" }, { "path": "../../../src/plugins/kibana_react/tsconfig.json" }, { "path": "../../../src/plugins/management/tsconfig.json" }, - { "path": "../../../src/plugins/security_oss/tsconfig.json" }, + { "path": "../../../src/plugins/share/tsconfig.json" }, { "path": "../../../src/plugins/usage_collection/tsconfig.json" } ] } diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index 52c82f57d9ec33..d2120faf09dfbb 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -334,7 +334,7 @@ export const ELASTIC_NAME = 'estc'; export const METADATA_TRANSFORM_STATS_URL = `/api/transform/transforms/${METADATA_TRANSFORMS_PATTERN}/_stats`; -export const HOST_RISK_SCORES_INDEX = 'ml_host_risk_score_latest'; +export const RISKY_HOSTS_INDEX_PREFIX = 'ml_host_risk_score_latest_'; export const TRANSFORM_STATES = { ABORTING: 'aborting', diff --git a/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts b/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts index f7f3df31db237a..be5fd3b5c4dc54 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts @@ -5,10 +5,14 @@ * 2.0. */ -import { IFieldSubType } from '@kbn/es-query'; -import type { IIndexPattern } from 'src/plugins/data/public'; -import { IEsSearchRequest, IEsSearchResponse } from '../../../../../../src/plugins/data/common'; -import { DocValueFields, Maybe } from '../common'; +import type { IFieldSubType } from '@kbn/es-query'; + +import type { + IEsSearchRequest, + IEsSearchResponse, + IIndexPattern, +} from '../../../../../../src/plugins/data/common'; +import type { DocValueFields, Maybe } from '../common'; interface FieldInfo { category: string; @@ -66,12 +70,7 @@ export interface BrowserField { name: string; searchable: boolean; type: string; - subType?: { - [key: string]: unknown; - nested?: { - path: string; - }; - }; + subType?: IFieldSubType; } export type BrowserFields = Readonly>>; diff --git a/x-pack/plugins/security_solution/cypress/integration/overview/risky_hosts_panel.spec.ts b/x-pack/plugins/security_solution/cypress/integration/overview/risky_hosts_panel.spec.ts index df57f7cc8d0504..1c55a38b324953 100644 --- a/x-pack/plugins/security_solution/cypress/integration/overview/risky_hosts_panel.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/overview/risky_hosts_panel.spec.ts @@ -17,8 +17,12 @@ import { import { loginAndWaitForPage } from '../../tasks/login'; import { OVERVIEW_URL } from '../../urls/navigation'; import { cleanKibana } from '../../tasks/common'; +import { changeSpace } from '../../tasks/kibana_navigation'; +import { createSpace, removeSpace } from '../../tasks/api_calls/spaces'; import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver'; +const testSpaceName = 'test'; + describe('Risky Hosts Link Panel', () => { before(() => { cleanKibana(); @@ -40,10 +44,12 @@ describe('Risky Hosts Link Panel', () => { describe('enabled module', () => { before(() => { esArchiverLoad('risky_hosts'); + createSpace(testSpaceName); }); after(() => { esArchiverUnload('risky_hosts'); + removeSpace(testSpaceName); }); it('renders disabled dashboard module as expected when there are no hosts in the selected time period', () => { @@ -57,13 +63,19 @@ describe('Risky Hosts Link Panel', () => { cy.get(`${OVERVIEW_RISKY_HOSTS_TOTAL_EVENT_COUNT}`).should('have.text', 'Showing: 0 hosts'); }); - it('renders dashboard module as expected when there are hosts in the selected time period', () => { + it('renders space aware dashboard module as expected when there are hosts in the selected time period', () => { loginAndWaitForPage(OVERVIEW_URL); cy.get( `${OVERVIEW_RISKY_HOSTS_LINKS} ${OVERVIEW_RISKY_HOSTS_LINKS_WARNING_INNER_PANEL}` ).should('not.exist'); cy.get(`${OVERVIEW_RISKY_HOSTS_VIEW_DASHBOARD_BUTTON}`).should('be.disabled'); cy.get(`${OVERVIEW_RISKY_HOSTS_TOTAL_EVENT_COUNT}`).should('have.text', 'Showing: 1 host'); + + changeSpace(testSpaceName); + cy.visit(`/s/${testSpaceName}${OVERVIEW_URL}`); + cy.get(`${OVERVIEW_RISKY_HOSTS_VIEW_DASHBOARD_BUTTON}`).should('be.disabled'); + cy.get(`${OVERVIEW_RISKY_HOSTS_TOTAL_EVENT_COUNT}`).should('have.text', 'Showing: 0 hosts'); + cy.get(`${OVERVIEW_RISKY_HOSTS_ENABLE_MODULE_BUTTON}`).should('exist'); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/screens/kibana_navigation.ts b/x-pack/plugins/security_solution/cypress/screens/kibana_navigation.ts index 36b870598eff44..c20f4bd054a7c7 100644 --- a/x-pack/plugins/security_solution/cypress/screens/kibana_navigation.ts +++ b/x-pack/plugins/security_solution/cypress/screens/kibana_navigation.ts @@ -25,3 +25,7 @@ export const OVERVIEW_PAGE = export const TIMELINES_PAGE = '[data-test-subj="collapsibleNavGroup-securitySolution"] [title="Timelines"]'; + +export const SPACES_BUTTON = '[data-test-subj="spacesNavSelector"]'; + +export const getGoToSpaceMenuItem = (space: string) => `[data-test-subj="${space}-gotoSpace"]`; diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/spaces.ts b/x-pack/plugins/security_solution/cypress/tasks/api_calls/spaces.ts new file mode 100644 index 00000000000000..cd12fab70a8914 --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/tasks/api_calls/spaces.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 createSpace = (id: string) => { + cy.request({ + method: 'POST', + url: 'api/spaces/space', + body: { + id, + name: id, + }, + headers: { 'kbn-xsrf': 'cypress-creds' }, + }); +}; + +export const removeSpace = (id: string) => { + cy.request(`/api/spaces/space/${id}`); +}; diff --git a/x-pack/plugins/security_solution/cypress/tasks/kibana_navigation.ts b/x-pack/plugins/security_solution/cypress/tasks/kibana_navigation.ts index 3b3fc0c6da4e4f..43630e63ebfe20 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/kibana_navigation.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/kibana_navigation.ts @@ -5,7 +5,11 @@ * 2.0. */ -import { KIBANA_NAVIGATION_TOGGLE } from '../screens/kibana_navigation'; +import { + KIBANA_NAVIGATION_TOGGLE, + SPACES_BUTTON, + getGoToSpaceMenuItem, +} from '../screens/kibana_navigation'; export const navigateFromKibanaCollapsibleTo = (page: string) => { cy.get(page).click(); @@ -14,3 +18,9 @@ export const navigateFromKibanaCollapsibleTo = (page: string) => { export const openKibanaNavigation = () => { cy.get(KIBANA_NAVIGATION_TOGGLE).click(); }; + +export const changeSpace = (space: string) => { + cy.get(`${SPACES_BUTTON}`).click(); + cy.get(getGoToSpaceMenuItem(space)).click(); + cy.get(`[data-test-subj="space-avatar-${space}"]`).should('exist'); +}; diff --git a/x-pack/plugins/security_solution/public/app/types.ts b/x-pack/plugins/security_solution/public/app/types.ts index 81f6de296d6a51..1942d2f836b1c9 100644 --- a/x-pack/plugins/security_solution/public/app/types.ts +++ b/x-pack/plugins/security_solution/public/app/types.ts @@ -12,7 +12,6 @@ import { Action, Store, Dispatch, - PreloadedState, StateFromReducersMapObject, CombinedState, } from 'redux'; @@ -39,7 +38,7 @@ import { TimelineState } from '../timelines/store/timeline/types'; export { SecurityPageName } from '../../common/constants'; export interface SecuritySubPluginStore { - initialState: Record; + initialState: Record; reducer: Record>; middleware?: Array>>>; } @@ -70,14 +69,12 @@ export interface SecuritySubPluginWithStore - > + initialState: CombinedState< + StateFromReducersMapObject< + /** SubPluginsInitReducer, being an interface, will not work in `StateFromReducersMapObject`. + * Picking its keys does the trick. + **/ + Pick > >; reducer: SubPluginsInitReducer; diff --git a/x-pack/plugins/security_solution/public/common/store/reducer.test.ts b/x-pack/plugins/security_solution/public/common/store/reducer.test.ts index d2808a02c86218..6b4d61035258db 100644 --- a/x-pack/plugins/security_solution/public/common/store/reducer.test.ts +++ b/x-pack/plugins/security_solution/public/common/store/reducer.test.ts @@ -6,6 +6,7 @@ */ import { parseExperimentalConfigValue } from '../../..//common/experimental_features'; +import { SecuritySubPlugins } from '../../app/types'; import { createInitialState } from './reducer'; jest.mock('../lib/kibana', () => ({ @@ -16,30 +17,28 @@ jest.mock('../lib/kibana', () => ({ describe('createInitialState', () => { describe('sourcerer -> default -> indicesExist', () => { + const mockPluginState = {} as Omit< + SecuritySubPlugins['store']['initialState'], + 'app' | 'dragAndDrop' | 'inputs' | 'sourcerer' + >; test('indicesExist should be TRUE if configIndexPatterns is NOT empty', () => { - const initState = createInitialState( - {}, - { - kibanaIndexPatterns: [{ id: '1234567890987654321', title: 'mock-kibana' }], - configIndexPatterns: ['auditbeat-*', 'filebeat'], - signalIndexName: 'siem-signals-default', - enableExperimental: parseExperimentalConfigValue([]), - } - ); + const initState = createInitialState(mockPluginState, { + kibanaIndexPatterns: [{ id: '1234567890987654321', title: 'mock-kibana' }], + configIndexPatterns: ['auditbeat-*', 'filebeat'], + signalIndexName: 'siem-signals-default', + enableExperimental: parseExperimentalConfigValue([]), + }); expect(initState.sourcerer?.sourcererScopes.default.indicesExist).toEqual(true); }); test('indicesExist should be FALSE if configIndexPatterns is empty', () => { - const initState = createInitialState( - {}, - { - kibanaIndexPatterns: [{ id: '1234567890987654321', title: 'mock-kibana' }], - configIndexPatterns: [], - signalIndexName: 'siem-signals-default', - enableExperimental: parseExperimentalConfigValue([]), - } - ); + const initState = createInitialState(mockPluginState, { + kibanaIndexPatterns: [{ id: '1234567890987654321', title: 'mock-kibana' }], + configIndexPatterns: [], + signalIndexName: 'siem-signals-default', + enableExperimental: parseExperimentalConfigValue([]), + }); expect(initState.sourcerer?.sourcererScopes.default.indicesExist).toEqual(false); }); diff --git a/x-pack/plugins/security_solution/public/common/store/reducer.ts b/x-pack/plugins/security_solution/public/common/store/reducer.ts index d5633ee84d6d42..4a6009b2e41a8b 100644 --- a/x-pack/plugins/security_solution/public/common/store/reducer.ts +++ b/x-pack/plugins/security_solution/public/common/store/reducer.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { combineReducers, PreloadedState, AnyAction, Reducer } from 'redux'; +import { combineReducers, AnyAction, Reducer } from 'redux'; import { appReducer, initialAppState } from './app'; import { dragAndDropReducer, initialDragAndDropState } from './drag_and_drop'; @@ -34,7 +34,10 @@ export type SubPluginsInitReducer = HostsPluginReducer & * Factory for the 'initialState' that is used to preload state into the Security App's redux store. */ export const createInitialState = ( - pluginsInitState: SecuritySubPlugins['store']['initialState'], + pluginsInitState: Omit< + SecuritySubPlugins['store']['initialState'], + 'app' | 'dragAndDrop' | 'inputs' | 'sourcerer' + >, { kibanaIndexPatterns, configIndexPatterns, @@ -46,11 +49,11 @@ export const createInitialState = ( signalIndexName: string | null; enableExperimental: ExperimentalFeatures; } -): PreloadedState => { - const preloadedState: PreloadedState = { +): State => { + const preloadedState: State = { + ...pluginsInitState, app: { ...initialAppState, enableExperimental }, dragAndDrop: initialDragAndDropState, - ...pluginsInitState, inputs: createInitialInputsState(), sourcerer: { ...sourcererModel.initialSourcererState, @@ -66,6 +69,7 @@ export const createInitialState = ( signalIndexName, }, }; + return preloadedState; }; diff --git a/x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts b/x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts index 26497c7f6ee3ba..8f7fbd99f932d1 100644 --- a/x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts +++ b/x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts @@ -27,7 +27,7 @@ export interface ManageScope { docValueFields: DocValueFields[]; errorMessage: string | null; id: SourcererScopeName; - indexPattern: IIndexPattern; + indexPattern: Omit; indicesExist: boolean | undefined | null; loading: boolean; selectedPatterns: string[]; @@ -37,9 +37,7 @@ export interface ManageScopeInit extends Partial { id: SourcererScopeName; } -export type SourcererScopeById = { - [id in SourcererScopeName]: ManageScope; -}; +export type SourcererScopeById = Record; export type KibanaIndexPatterns = Array<{ id: string; title: string }>; @@ -51,7 +49,16 @@ export interface SourcererModel { sourcererScopes: SourcererScopeById; } -export const initSourcererScope = { +export const initSourcererScope: Pick< + ManageScope, + | 'browserFields' + | 'docValueFields' + | 'errorMessage' + | 'indexPattern' + | 'indicesExist' + | 'loading' + | 'selectedPatterns' +> = { browserFields: EMPTY_BROWSER_FIELDS, docValueFields: EMPTY_DOCVALUE_FIELD, errorMessage: null, diff --git a/x-pack/plugins/security_solution/public/common/store/store.ts b/x-pack/plugins/security_solution/public/common/store/store.ts index e253ae1bbaf985..a289eaf5cf853e 100644 --- a/x-pack/plugins/security_solution/public/common/store/store.ts +++ b/x-pack/plugins/security_solution/public/common/store/store.ts @@ -49,7 +49,7 @@ let store: Store | null = null; * Factory for Security App's redux store. */ export const createStore = ( - state: PreloadedState, + state: State, pluginsReducer: SubPluginsInitReducer, kibana: Observable, storage: Storage, @@ -74,7 +74,7 @@ export const createStore = ( store = createReduxStore( createReducer(pluginsReducer), - state, + state as PreloadedState, composeEnhancers( applyMiddleware(epicMiddleware, telemetryMiddleware, ...(additionalMiddleware ?? [])) ) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx index ad5a85a03464ee..6b05ee6403db38 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx @@ -11,9 +11,12 @@ import { EuiText, EuiHealth, EuiToolTip, + EuiIcon, + EuiLink, } from '@elastic/eui'; -import { FormattedRelative } from '@kbn/i18n/react'; +import { FormattedMessage, FormattedRelative } from '@kbn/i18n/react'; import * as H from 'history'; +import { sum } from 'lodash'; import React, { Dispatch } from 'react'; import { isMlRule } from '../../../../../../common/machine_learning/helpers'; @@ -36,10 +39,11 @@ import { RulesTableAction } from '../../../../containers/detection_engine/rules/ import { LocalizedDateTooltip } from '../../../../../common/components/localized_date_tooltip'; import { LinkAnchor } from '../../../../../common/components/links'; import { getToolTipContent, canEditRuleWithActions } from '../../../../../common/utils/privileges'; +import { PopoverTooltip } from './popover_tooltip'; import { TagsDisplay } from './tag_display'; import { getRuleStatusText } from '../../../../../../common/detection_engine/utils'; import { APP_ID, SecurityPageName } from '../../../../../../common/constants'; -import { NavigateToAppOptions } from '../../../../../../../../../src/core/public'; +import { DocLinksStart, NavigateToAppOptions } from '../../../../../../../../../src/core/public'; export const getActions = ( dispatch: React.Dispatch, @@ -312,7 +316,8 @@ export const getColumns = ({ export const getMonitoringColumns = ( navigateToApp: (appId: string, options?: NavigateToAppOptions | undefined) => Promise, - formatUrl: FormatUrl + formatUrl: FormatUrl, + docLinks: DocLinksStart ): RulesStatusesColumns[] => { const cols: RulesStatusesColumns[] = [ { @@ -344,12 +349,17 @@ export const getMonitoringColumns = ( }, { field: 'current_status.bulk_create_time_durations', - name: i18n.COLUMN_INDEXING_TIMES, + name: ( + <> + {i18n.COLUMN_INDEXING_TIMES}{' '} + + + + + ), render: (value: RuleStatus['current_status']['bulk_create_time_durations']) => ( - {value != null && value.length > 0 - ? Math.max(...value?.map((item) => Number.parseFloat(item))) - : getEmptyTagValue()} + {value?.length ? sum(value.map(Number)).toFixed() : getEmptyTagValue()} ), truncateText: true, @@ -357,12 +367,17 @@ export const getMonitoringColumns = ( }, { field: 'current_status.search_after_time_durations', - name: i18n.COLUMN_QUERY_TIMES, + name: ( + <> + {i18n.COLUMN_QUERY_TIMES}{' '} + + + + + ), render: (value: RuleStatus['current_status']['search_after_time_durations']) => ( - {value != null && value.length > 0 - ? Math.max(...value?.map((item) => Number.parseFloat(item))) - : getEmptyTagValue()} + {value?.length ? sum(value.map(Number)).toFixed() : getEmptyTagValue()} ), truncateText: true, @@ -370,7 +385,28 @@ export const getMonitoringColumns = ( }, { field: 'current_status.gap', - name: i18n.COLUMN_GAP, + name: ( + <> + {i18n.COLUMN_GAP} + + +

+ + {'see documentation'} + + ), + }} + /> +

+
+
+ + ), render: (value: RuleStatus['current_status']['gap']) => ( {value ?? getEmptyTagValue()} diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/popover_tooltip.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/popover_tooltip.tsx new file mode 100644 index 00000000000000..5cf0a0c0b28fc3 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/popover_tooltip.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState } from 'react'; +import { EuiPopover, EuiButtonIcon } from '@elastic/eui'; +import * as i18n from '../translations'; + +interface PopoverTooltipProps { + columnName: string; + children: React.ReactNode; +} + +/** + * Table column tooltip component utilizing EuiPopover for rich content like documentation links + * @param columnName string Name of column to use as aria-label of button + * @param children React.ReactNode of content to display in popover tooltip + */ +const PopoverTooltipComponent = ({ columnName, children }: PopoverTooltipProps) => { + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + return ( + setIsPopoverOpen(false)} + button={ + setIsPopoverOpen(!isPopoverOpen)} + size="s" + color="primary" + iconType="questionInCircle" + /> + } + > + {children} + + ); +}; + +export const PopoverTooltip = React.memo(PopoverTooltipComponent); + +PopoverTooltip.displayName = 'PopoverTooltip'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx index f32321a0a03dc1..9d9425cdabe63a 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx @@ -96,6 +96,7 @@ export const RulesTables = React.memo( setRefreshRulesData, selectedTab, }) => { + const docLinks = useKibana().services.docLinks; const [initLoading, setInitLoading] = useState(true); const { @@ -299,8 +300,8 @@ export const RulesTables = React.memo( ]); const monitoringColumns = useMemo( - () => getMonitoringColumns(navigateToApp, formatUrl), - [navigateToApp, formatUrl] + () => getMonitoringColumns(navigateToApp, formatUrl, docLinks), + [navigateToApp, formatUrl, docLinks] ); useEffect(() => { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts index 28ed14774acf66..53efe28cba49c9 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts @@ -13,6 +13,11 @@ export const BACK_TO_DETECTIONS = i18n.translate( defaultMessage: 'Back to detections', } ); +export const POPOVER_TOOLTIP_ARIA_LABEL = (columnName: string) => + i18n.translate('xpack.securitySolution.detectionEngine.rules.popoverTooltip.ariaLabel', { + defaultMessage: 'Tooltip for column: {columnName}', + values: { columnName }, + }); export const IMPORT_RULE = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.importRuleTitle', @@ -364,6 +369,13 @@ export const COLUMN_INDEXING_TIMES = i18n.translate( } ); +export const COLUMN_INDEXING_TIMES_TOOLTIP = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.columns.indexingTimesTooltip', + { + defaultMessage: 'Total time spent indexing alerts during last Rule execution', + } +); + export const COLUMN_QUERY_TIMES = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.columns.queryTimes', { @@ -371,6 +383,13 @@ export const COLUMN_QUERY_TIMES = i18n.translate( } ); +export const COLUMN_QUERY_TIMES_TOOLTIP = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.columns.queryTimesTooltip', + { + defaultMessage: 'Total time spent querying source indices during last Rule execution', + } +); + export const COLUMN_GAP = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.columns.gap', { diff --git a/x-pack/plugins/security_solution/public/helpers.test.ts b/x-pack/plugins/security_solution/public/helpers.test.ts index eaaf518d486ad9..f2e37cd995a4fe 100644 --- a/x-pack/plugins/security_solution/public/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/helpers.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { parseRoute } from './helpers'; +import { parseRoute, getHostRiskIndex } from './helpers'; describe('public helpers parseRoute', () => { it('should properly parse hash route', () => { @@ -54,3 +54,9 @@ describe('public helpers parseRoute', () => { }); }); }); + +describe('public helpers export getHostRiskIndex', () => { + it('should properly return index if space is specified', () => { + expect(getHostRiskIndex('testName')).toEqual('ml_host_risk_score_latest_testName'); + }); +}); diff --git a/x-pack/plugins/security_solution/public/helpers.ts b/x-pack/plugins/security_solution/public/helpers.ts index 9d842e0c0a1286..aba46cffee193d 100644 --- a/x-pack/plugins/security_solution/public/helpers.ts +++ b/x-pack/plugins/security_solution/public/helpers.ts @@ -9,7 +9,14 @@ import { isEmpty } from 'lodash/fp'; import { matchPath } from 'react-router-dom'; import { CoreStart } from '../../../../src/core/public'; -import { ALERTS_PATH, APP_ID, EXCEPTIONS_PATH, RULES_PATH, UEBA_PATH } from '../common/constants'; +import { + ALERTS_PATH, + APP_ID, + EXCEPTIONS_PATH, + RULES_PATH, + UEBA_PATH, + RISKY_HOSTS_INDEX_PREFIX, +} from '../common/constants'; import { FactoryQueryTypes, StrategyResponseType, @@ -147,3 +154,7 @@ export const isDetectionsPath = (pathname: string): boolean => { strict: false, }); }; + +export const getHostRiskIndex = (spaceId: string): string => { + return `${RISKY_HOSTS_INDEX_PREFIX}${spaceId}`; +}; diff --git a/x-pack/plugins/security_solution/public/management/index.ts b/x-pack/plugins/security_solution/public/management/index.ts index 326f8471aa6219..3e2c8b0ca2ec8f 100644 --- a/x-pack/plugins/security_solution/public/management/index.ts +++ b/x-pack/plugins/security_solution/public/management/index.ts @@ -42,7 +42,12 @@ export class Management { routes, store: { initialState: { - management: undefined, + /** + * Cast the state to ManagementState for compatibility with + * the subplugin architecture (which expects initialize state.) + * but you do not need it because this plugin is doing it through its middleware + */ + management: {} as ManagementState, }, /** * Cast the ImmutableReducer to a regular reducer for compatibility with diff --git a/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_hosts_risk_score.ts b/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_hosts_risk_score.ts index 75cf51194ab65b..af663bb74f54a0 100644 --- a/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_hosts_risk_score.ts +++ b/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_hosts_risk_score.ts @@ -12,12 +12,11 @@ import { useDispatch } from 'react-redux'; import { useAppToasts } from '../../../common/hooks/use_app_toasts'; import { useKibana } from '../../../common/lib/kibana'; import { inputsActions } from '../../../common/store/actions'; - -import { HOST_RISK_SCORES_INDEX } from '../../../../common/constants'; import { isIndexNotFoundError } from '../../../common/utils/exceptions'; import { HostsRiskScore } from '../../../../common'; import { useHostsRiskScoreComplete } from './use_hosts_risk_score_complete'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; +import { getHostRiskIndex } from '../../../helpers'; export const QUERY_ID = 'host_risk_score'; const noop = () => {}; @@ -50,7 +49,7 @@ export const useHostsRiskScore = ({ const [loading, setLoading] = useState(riskyHostsFeatureEnabled); const { addError } = useAppToasts(); - const { data } = useKibana().services; + const { data, spaces } = useKibana().services; const dispatch = useDispatch(); @@ -99,14 +98,18 @@ export const useHostsRiskScore = ({ useEffect(() => { if (riskyHostsFeatureEnabled && (hostName || timerange)) { - start({ - data, - timerange: timerange ? { to: timerange.to, from: timerange.from, interval: '' } : undefined, - hostName, - defaultIndex: [HOST_RISK_SCORES_INDEX], + spaces.getActiveSpace().then((space) => { + start({ + data, + timerange: timerange + ? { to: timerange.to, from: timerange.from, interval: '' } + : undefined, + hostName, + defaultIndex: [getHostRiskIndex(space.id)], + }); }); } - }, [start, data, timerange, hostName, riskyHostsFeatureEnabled]); + }, [start, data, timerange, hostName, riskyHostsFeatureEnabled, spaces]); if ((!hostName && !timerange) || !riskyHostsFeatureEnabled) { return null; diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index fe746d2e8e8d87..718487ccf7fc66 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -293,7 +293,7 @@ export class Plugin implements IPlugin; hosts: ReturnType; network: ReturnType; - // TODO: Steph/ueba require ueba once no longer experimental - ueba?: ReturnType; + ueba: ReturnType; overview: ReturnType; timelines: ReturnType; management: ReturnType; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/threshold.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/threshold.ts index 554672806c12e7..2d33ce7e155b4e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/threshold.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/threshold.ts @@ -25,7 +25,6 @@ import { TypeOfFieldMap } from '../../../../../../rule_registry/common/field_map import { SERVER_APP_ID } from '../../../../../common/constants'; import { ANCHOR_DATE } from '../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; import { getListArrayMock } from '../../../../../common/detection_engine/schemas/types/lists.mock'; -import { sampleDocNoSortId } from '../../signals/__mocks__/es_results'; import { flattenWithPrefix } from '../factories/utils/flatten_with_prefix'; import { RulesFieldMap } from '../field_maps'; import { @@ -60,19 +59,8 @@ export const mockThresholdResults = { { key: 'tardigrade', doc_count: 3, - top_threshold_hits: { - hits: { - total: { - value: 1, - relation: 'eq', - }, - hits: [ - { - ...sampleDocNoSortId(), - 'host.name': 'tardigrade', - }, - ], - }, + max_timestamp: { + value_as_string: '2020-04-20T21:26:30.000Z', }, cardinality_count: { value: 3, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.test.ts index 79c2d86f35e7bc..2d0907b0450147 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.test.ts @@ -7,7 +7,7 @@ import { loggingSystemMock } from '../../../../../../../../src/core/server/mocks'; import { ThresholdNormalized } from '../../../../../common/detection_engine/schemas/common/schemas'; -import { sampleDocNoSortId, sampleDocSearchResultsNoSortId } from '../__mocks__/es_results'; +import { sampleDocSearchResultsNoSortId } from '../__mocks__/es_results'; import { sampleThresholdSignalHistory } from '../__mocks__/threshold_signal_history.mock'; import { calculateThresholdSignalUuid } from '../utils'; import { transformThresholdResultsToEcs } from './bulk_create_threshold_signals'; @@ -40,10 +40,8 @@ describe('transformThresholdNormalizedResultsToEcs', () => { { key: 'garden-gnomes', doc_count: 12, - top_threshold_hits: { - hits: { - hits: [sampleDocNoSortId('abcd')], - }, + max_timestamp: { + value_as_string: '2020-04-20T21:27:45+0000', }, cardinality_count: { value: 7, @@ -208,10 +206,8 @@ describe('transformThresholdNormalizedResultsToEcs', () => { { key: '', doc_count: 15, - top_threshold_hits: { - hits: { - hits: [sampleDocNoSortId('abcd')], - }, + max_timestamp: { + value_as_string: '2020-04-20T21:27:45+0000', }, cardinality_count: { value: 7, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.ts index ce8ee4542d6039..31bf7674b4f929 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.ts @@ -4,6 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + +import { TIMESTAMP } from '@kbn/rule-data-utils'; + import { get } from 'lodash/fp'; import set from 'set-value'; import { @@ -96,7 +99,7 @@ const getTransformedHits = ( ...val.terms, ].filter((term) => term.field != null), cardinality: val.cardinality, - topThresholdHits: val.topThresholdHits, + maxTimestamp: val.maxTimestamp, docCount: val.docCount, }; acc.push(el as MultiAggBucket); @@ -117,7 +120,7 @@ const getTransformedHits = ( }, ] : undefined, - topThresholdHits: bucket.top_threshold_hits, + maxTimestamp: bucket.max_timestamp.value_as_string, docCount: bucket.doc_count, }; acc.push(el as MultiAggBucket); @@ -132,28 +135,15 @@ const getTransformedHits = ( 0, aggParts.field ).reduce((acc: Array>, bucket) => { - const hit = bucket.topThresholdHits?.hits.hits[0]; - if (hit == null) { - return acc; - } - - const timestampArray = get(timestampOverride ?? '@timestamp', hit.fields); - if (timestampArray == null) { - return acc; - } - - const timestamp = timestampArray[0]; - if (typeof timestamp !== 'string') { - return acc; - } - const termsHash = getThresholdTermsHash(bucket.terms); const signalHit = signalHistory[termsHash]; const source = { - '@timestamp': timestamp, + [TIMESTAMP]: bucket.maxTimestamp, ...bucket.terms.reduce((termAcc, term) => { if (!term.field.startsWith('signal.')) { + // We don't want to overwrite `signal.*` fields. + // See: https://github.com/elastic/kibana/issues/83218 return { ...termAcc, [term.field]: term.value, @@ -170,7 +160,7 @@ const getTransformedHits = ( // the `original_time` of the signal (the timestamp of the latest event // in the set). from: - signalHit?.lastSignalTimestamp != null ? new Date(signalHit!.lastSignalTimestamp) : from, + signalHit?.lastSignalTimestamp != null ? new Date(signalHit.lastSignalTimestamp) : from, }, }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.test.ts index 41d46925770bd5..bb2e8d3650e8aa 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.test.ts @@ -58,22 +58,9 @@ describe('findThresholdSignals', () => { min_doc_count: 100, }, aggs: { - top_threshold_hits: { - top_hits: { - sort: [ - { - '@timestamp': { - order: 'desc', - }, - }, - ], - fields: [ - { - field: '*', - include_unmapped: true, - }, - ], - size: 1, + max_timestamp: { + max: { + field: '@timestamp', }, }, }, @@ -108,22 +95,9 @@ describe('findThresholdSignals', () => { size: 10000, }, aggs: { - top_threshold_hits: { - top_hits: { - sort: [ - { - '@timestamp': { - order: 'desc', - }, - }, - ], - fields: [ - { - field: '*', - include_unmapped: true, - }, - ], - size: 1, + max_timestamp: { + max: { + field: '@timestamp', }, }, }, @@ -166,22 +140,9 @@ describe('findThresholdSignals', () => { size: 10000, }, aggs: { - top_threshold_hits: { - top_hits: { - sort: [ - { - '@timestamp': { - order: 'desc', - }, - }, - ], - fields: [ - { - field: '*', - include_unmapped: true, - }, - ], - size: 1, + max_timestamp: { + max: { + field: '@timestamp', }, }, }, @@ -245,22 +206,9 @@ describe('findThresholdSignals', () => { script: 'params.cardinalityCount >= 2', }, }, - top_threshold_hits: { - top_hits: { - sort: [ - { - '@timestamp': { - order: 'desc', - }, - }, - ], - fields: [ - { - field: '*', - include_unmapped: true, - }, - ], - size: 1, + max_timestamp: { + max: { + field: '@timestamp', }, }, }, @@ -319,22 +267,9 @@ describe('findThresholdSignals', () => { script: 'params.cardinalityCount >= 5', }, }, - top_threshold_hits: { - top_hits: { - sort: [ - { - '@timestamp': { - order: 'desc', - }, - }, - ], - fields: [ - { - field: '*', - include_unmapped: true, - }, - ], - size: 1, + max_timestamp: { + max: { + field: '@timestamp', }, }, }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts index 740ba281cfcfb1..ad0ff99c019afe 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts @@ -6,6 +6,7 @@ */ import { set } from '@elastic/safer-lodash-set'; +import { TIMESTAMP } from '@kbn/rule-data-utils'; import { ThresholdNormalized, @@ -50,22 +51,9 @@ export const findThresholdSignals = async ({ }> => { // Leaf aggregations used below const leafAggs = { - top_threshold_hits: { - top_hits: { - sort: [ - { - [timestampOverride ?? '@timestamp']: { - order: 'desc' as const, - }, - }, - ], - fields: [ - { - field: '*', - include_unmapped: true, - }, - ], - size: 1, + max_timestamp: { + max: { + field: timestampOverride != null ? timestampOverride : TIMESTAMP, }, }, ...(threshold.cardinality?.length diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts index fc6b42c38549e0..c1e7e23c3b161c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts @@ -19,7 +19,7 @@ import { AlertExecutorOptions, AlertServices, } from '../../../../../alerting/server'; -import { BaseSearchResponse, SearchHit, TermAggregationBucket } from '../../types'; +import { TermAggregationBucket } from '../../types'; import { EqlSearchResponse, BaseHit, @@ -332,7 +332,9 @@ export interface SearchAfterAndBulkCreateReturnType { } export interface ThresholdAggregationBucket extends TermAggregationBucket { - top_threshold_hits: BaseSearchResponse; + max_timestamp: { + value_as_string: string; + }; cardinality_count: { value: number; }; @@ -348,13 +350,7 @@ export interface MultiAggBucket { value: string; }>; docCount: number; - topThresholdHits?: - | { - hits: { - hits: SearchHit[]; - }; - } - | undefined; + maxTimestamp: string; } export interface ThresholdQueryBucket extends TermAggregationBucket { diff --git a/x-pack/plugins/security_solution/server/lib/types.ts b/x-pack/plugins/security_solution/server/lib/types.ts index 31211869d054d0..2a1452e7b2fd3a 100644 --- a/x-pack/plugins/security_solution/server/lib/types.ts +++ b/x-pack/plugins/security_solution/server/lib/types.ts @@ -74,10 +74,8 @@ export type SearchHit = SearchResponse['hits']['hits'][0]; export interface TermAggregationBucket { key: string; doc_count: number; - top_threshold_hits?: { - hits: { - hits: SearchHit[]; - }; + max_timestamp: { + value_as_string: string; }; cardinality_count?: { value: number; diff --git a/x-pack/plugins/spaces/public/constants.ts b/x-pack/plugins/spaces/public/constants.ts index 64803ff9d4bc87..b513a8affacf82 100644 --- a/x-pack/plugins/spaces/public/constants.ts +++ b/x-pack/plugins/spaces/public/constants.ts @@ -19,3 +19,7 @@ export const getSpacesFeatureDescription = () => { return spacesFeatureDescription; }; + +export const DEFAULT_OBJECT_NOUN = i18n.translate('xpack.spaces.shareToSpace.objectNoun', { + defaultMessage: 'object', +}); diff --git a/x-pack/plugins/spaces/public/index.ts b/x-pack/plugins/spaces/public/index.ts index d13f8f48e6719f..fe04358e30483d 100644 --- a/x-pack/plugins/spaces/public/index.ts +++ b/x-pack/plugins/spaces/public/index.ts @@ -20,8 +20,9 @@ export type { CopyToSpaceSavedObjectTarget, } from './copy_saved_objects_to_space'; +export type { LegacyUrlConflictProps, EmbeddableLegacyUrlConflictProps } from './legacy_urls'; + export type { - LegacyUrlConflictProps, ShareToSpaceFlyoutProps, ShareToSpaceSavedObjectTarget, } from './share_saved_objects_to_space'; diff --git a/x-pack/plugins/spaces/public/legacy_urls/components/embeddable_legacy_url_conflict.tsx b/x-pack/plugins/spaces/public/legacy_urls/components/embeddable_legacy_url_conflict.tsx new file mode 100644 index 00000000000000..24f36723f9782f --- /dev/null +++ b/x-pack/plugins/spaces/public/legacy_urls/components/embeddable_legacy_url_conflict.tsx @@ -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. + */ + +import React from 'react'; + +import type { EmbeddableLegacyUrlConflictProps } from '../types'; +import type { InternalProps } from './embeddable_legacy_url_conflict_internal'; + +export const getEmbeddableLegacyUrlConflict = async ( + internalProps: InternalProps +): Promise> => { + const { EmbeddableLegacyUrlConflictInternal } = await import( + './embeddable_legacy_url_conflict_internal' + ); + return (props: EmbeddableLegacyUrlConflictProps) => { + return ; + }; +}; diff --git a/x-pack/plugins/spaces/public/legacy_urls/components/embeddable_legacy_url_conflict_internal.tsx b/x-pack/plugins/spaces/public/legacy_urls/components/embeddable_legacy_url_conflict_internal.tsx new file mode 100644 index 00000000000000..8f86c2658cc3ca --- /dev/null +++ b/x-pack/plugins/spaces/public/legacy_urls/components/embeddable_legacy_url_conflict_internal.tsx @@ -0,0 +1,92 @@ +/* + * 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 { + EuiButtonEmpty, + EuiCallOut, + EuiCodeBlock, + EuiLink, + EuiSpacer, + EuiTextAlign, +} from '@elastic/eui'; +import React, { useState } from 'react'; +import useAsync from 'react-use/lib/useAsync'; + +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import type { StartServicesAccessor } from 'src/core/public'; + +import type { PluginsStart } from '../../plugin'; +import type { SpacesManager } from '../../spaces_manager'; +import type { EmbeddableLegacyUrlConflictProps } from '../types'; + +export interface InternalProps { + spacesManager: SpacesManager; + getStartServices: StartServicesAccessor; +} + +export const EmbeddableLegacyUrlConflictInternal = ( + props: InternalProps & EmbeddableLegacyUrlConflictProps +) => { + const { spacesManager, getStartServices, targetType, sourceId } = props; + + const [expandError, setExpandError] = useState(false); + + const { value: asyncParams } = useAsync(async () => { + const [{ docLinks }] = await getStartServices(); + const { id: targetSpace } = await spacesManager.getActiveSpace(); + const docLink = docLinks.links.spaces.kibanaDisableLegacyUrlAliasesApi; + const aliasJsonString = JSON.stringify({ targetSpace, targetType, sourceId }, null, 2); + return { docLink, aliasJsonString }; + }, [getStartServices, spacesManager]); + const { docLink, aliasJsonString } = asyncParams ?? {}; + + if (!aliasJsonString || !docLink) { + return null; + } + + return ( + <> + + + {expandError ? ( + + + {'_disable_legacy_url_aliases API'} + + ), + }} + /> + } + color="danger" + iconType="alert" + > + + {aliasJsonString} + + + + ) : ( + setExpandError(true)}> + {i18n.translate('xpack.spaces.embeddableLegacyUrlConflict.detailsButton', { + defaultMessage: `View details`, + })} + + )} + + ); +}; diff --git a/x-pack/plugins/spaces/public/legacy_urls/components/index.ts b/x-pack/plugins/spaces/public/legacy_urls/components/index.ts new file mode 100644 index 00000000000000..c23749da2e895b --- /dev/null +++ b/x-pack/plugins/spaces/public/legacy_urls/components/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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { getEmbeddableLegacyUrlConflict } from './embeddable_legacy_url_conflict'; +export { getLegacyUrlConflict } from './legacy_url_conflict'; diff --git a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/legacy_url_conflict.tsx b/x-pack/plugins/spaces/public/legacy_urls/components/legacy_url_conflict.tsx similarity index 100% rename from x-pack/plugins/spaces/public/share_saved_objects_to_space/components/legacy_url_conflict.tsx rename to x-pack/plugins/spaces/public/legacy_urls/components/legacy_url_conflict.tsx diff --git a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/legacy_url_conflict_internal.test.tsx b/x-pack/plugins/spaces/public/legacy_urls/components/legacy_url_conflict_internal.test.tsx similarity index 100% rename from x-pack/plugins/spaces/public/share_saved_objects_to_space/components/legacy_url_conflict_internal.test.tsx rename to x-pack/plugins/spaces/public/legacy_urls/components/legacy_url_conflict_internal.test.tsx diff --git a/x-pack/plugins/spaces/public/legacy_urls/components/legacy_url_conflict_internal.tsx b/x-pack/plugins/spaces/public/legacy_urls/components/legacy_url_conflict_internal.tsx new file mode 100644 index 00000000000000..a108e44fefe6eb --- /dev/null +++ b/x-pack/plugins/spaces/public/legacy_urls/components/legacy_url_conflict_internal.tsx @@ -0,0 +1,135 @@ +/* + * 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 { + EuiButton, + EuiButtonEmpty, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiLink, + EuiSpacer, + EuiToolTip, +} from '@elastic/eui'; +import React, { useState } from 'react'; +import useAsync from 'react-use/lib/useAsync'; +import { first } from 'rxjs/operators'; + +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import type { StartServicesAccessor } from 'src/core/public'; + +import { DEFAULT_OBJECT_NOUN } from '../../constants'; +import type { PluginsStart } from '../../plugin'; +import type { LegacyUrlConflictProps } from '../types'; + +export interface InternalProps { + getStartServices: StartServicesAccessor; +} + +export const LegacyUrlConflictInternal = (props: InternalProps & LegacyUrlConflictProps) => { + const { + getStartServices, + objectNoun = DEFAULT_OBJECT_NOUN, + currentObjectId, + otherObjectId, + otherObjectPath, + } = props; + + const [isDismissed, setIsDismissed] = useState(false); + + const { value: asyncParams } = useAsync(async () => { + const [{ application: applicationStart, docLinks }] = await getStartServices(); + const appId = await applicationStart.currentAppId$.pipe(first()).toPromise(); // retrieve the most recent value from the BehaviorSubject + const docLink = docLinks.links.spaces.kibanaLegacyUrlAliases; + return { applicationStart, appId, docLink }; + }, [getStartServices]); + const { docLink, applicationStart, appId } = asyncParams ?? {}; + + if (!applicationStart || !appId || !docLink || isDismissed) { + return null; + } + + function clickLinkButton() { + applicationStart!.navigateToApp(appId!, { path: otherObjectPath }); + } + + function clickDismissButton() { + setIsDismissed(true); + } + + return ( + + } + > + + {i18n.translate('xpack.spaces.legacyUrlConflict.documentationLinkText', { + defaultMessage: 'Learn more', + })} + + ), + }} + /> + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/x-pack/plugins/spaces/public/legacy_urls/index.ts b/x-pack/plugins/spaces/public/legacy_urls/index.ts new file mode 100644 index 00000000000000..b79f65075ce568 --- /dev/null +++ b/x-pack/plugins/spaces/public/legacy_urls/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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { getEmbeddableLegacyUrlConflict, getLegacyUrlConflict } from './components'; +export { createRedirectLegacyUrl } from './redirect_legacy_url'; + +export type { EmbeddableLegacyUrlConflictProps, LegacyUrlConflictProps } from './types'; diff --git a/x-pack/plugins/spaces/public/share_saved_objects_to_space/utils/redirect_legacy_url.test.ts b/x-pack/plugins/spaces/public/legacy_urls/redirect_legacy_url.test.ts similarity index 100% rename from x-pack/plugins/spaces/public/share_saved_objects_to_space/utils/redirect_legacy_url.test.ts rename to x-pack/plugins/spaces/public/legacy_urls/redirect_legacy_url.test.ts diff --git a/x-pack/plugins/spaces/public/share_saved_objects_to_space/utils/redirect_legacy_url.ts b/x-pack/plugins/spaces/public/legacy_urls/redirect_legacy_url.ts similarity index 77% rename from x-pack/plugins/spaces/public/share_saved_objects_to_space/utils/redirect_legacy_url.ts rename to x-pack/plugins/spaces/public/legacy_urls/redirect_legacy_url.ts index d427b1bc052428..dbc3d68a4dde99 100644 --- a/x-pack/plugins/spaces/public/share_saved_objects_to_space/utils/redirect_legacy_url.ts +++ b/x-pack/plugins/spaces/public/legacy_urls/redirect_legacy_url.ts @@ -10,9 +10,9 @@ import { first } from 'rxjs/operators'; import { i18n } from '@kbn/i18n'; import type { StartServicesAccessor } from 'src/core/public'; -import type { PluginsStart } from '../../plugin'; -import type { SpacesApiUi } from '../../ui_api'; -import { DEFAULT_OBJECT_NOUN } from '../components/constants'; +import { DEFAULT_OBJECT_NOUN } from '../constants'; +import type { PluginsStart } from '../plugin'; +import type { SpacesApiUi } from '../ui_api'; export function createRedirectLegacyUrl( getStartServices: StartServicesAccessor @@ -22,10 +22,10 @@ export function createRedirectLegacyUrl( const { currentAppId$, navigateToApp } = application; const appId = await currentAppId$.pipe(first()).toPromise(); // retrieve the most recent value from the BehaviorSubject - const title = i18n.translate('xpack.spaces.shareToSpace.redirectLegacyUrlToast.title', { + const title = i18n.translate('xpack.spaces.redirectLegacyUrlToast.title', { defaultMessage: `We redirected you to a new URL`, }); - const text = i18n.translate('xpack.spaces.shareToSpace.redirectLegacyUrlToast.text', { + const text = i18n.translate('xpack.spaces.redirectLegacyUrlToast.text', { defaultMessage: `The {objectNoun} you're looking for has a new location. Use this URL from now on.`, values: { objectNoun }, }); diff --git a/x-pack/plugins/spaces/public/legacy_urls/types.ts b/x-pack/plugins/spaces/public/legacy_urls/types.ts new file mode 100644 index 00000000000000..b3a80627b5b48f --- /dev/null +++ b/x-pack/plugins/spaces/public/legacy_urls/types.ts @@ -0,0 +1,46 @@ +/* + * 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. + */ + +/** + * Properties for the LegacyUrlConflict component. + */ +export interface LegacyUrlConflictProps { + /** + * The string that is used to describe the object in the callout, e.g., _There is a legacy URL for this page that points to a different + * **object**_. + * + * Default value is 'object'. + */ + objectNoun?: string; + /** + * The ID of the object that is currently shown on the page. + */ + currentObjectId: string; + /** + * The ID of the other object that the legacy URL alias points to. + */ + otherObjectId: string; + /** + * The path within your application to use for the new URL, optionally including `search` and/or `hash` URL components. Do not include + * `/app/my-app` or the current base path. + */ + otherObjectPath: string; +} + +/** + * Properties for the EmbeddableLegacyUrlConflict component. + */ +export interface EmbeddableLegacyUrlConflictProps { + /** + * The target type of the legacy URL alias. + */ + targetType: string; + /** + * The source ID of the legacy URL alias. + */ + sourceId: string; +} diff --git a/x-pack/plugins/spaces/public/lib/documentation_links.test.ts b/x-pack/plugins/spaces/public/lib/documentation_links.test.ts deleted file mode 100644 index 5ebaf0ebadaf6f..00000000000000 --- a/x-pack/plugins/spaces/public/lib/documentation_links.test.ts +++ /dev/null @@ -1,27 +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 { docLinksServiceMock } from 'src/core/public/mocks'; - -import { DocumentationLinksService } from './documentation_links'; - -describe('DocumentationLinksService', () => { - const setup = () => { - const docLinks = docLinksServiceMock.createStartContract(); - const service = new DocumentationLinksService(docLinks); - return { docLinks, service }; - }; - - describe('#getKibanaPrivilegesDocUrl', () => { - it('returns expected value', () => { - const { service } = setup(); - expect(service.getKibanaPrivilegesDocUrl()).toMatchInlineSnapshot( - `"https://www.elastic.co/guide/en/kibana/mocked-test-branch/kibana-privileges.html"` - ); - }); - }); -}); diff --git a/x-pack/plugins/spaces/public/lib/documentation_links.ts b/x-pack/plugins/spaces/public/lib/documentation_links.ts deleted file mode 100644 index 108be17fe84baa..00000000000000 --- a/x-pack/plugins/spaces/public/lib/documentation_links.ts +++ /dev/null @@ -1,20 +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 type { DocLinksStart } from 'src/core/public'; - -export class DocumentationLinksService { - private readonly kbnPrivileges: string; - - constructor(docLinks: DocLinksStart) { - this.kbnPrivileges = `${docLinks.links.security.kibanaPrivileges}`; - } - - public getKibanaPrivilegesDocUrl() { - return `${this.kbnPrivileges}`; - } -} diff --git a/x-pack/plugins/spaces/public/mocks.ts b/x-pack/plugins/spaces/public/mocks.ts index 76cafd4c7f5ae9..9146a0aa2c99b8 100644 --- a/x-pack/plugins/spaces/public/mocks.ts +++ b/x-pack/plugins/spaces/public/mocks.ts @@ -41,7 +41,7 @@ const createApiUiComponentsMock = () => { getSpaceList: jest.fn(), getLegacyUrlConflict: jest.fn(), getSpaceAvatar: jest.fn(), - getSavedObjectConflictMessage: jest.fn(), + getEmbeddableLegacyUrlConflict: jest.fn(), }; return mock; diff --git a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/get_saved_object_conflict_message.tsx b/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/get_saved_object_conflict_message.tsx deleted file mode 100644 index 66b2a5652057aa..00000000000000 --- a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/get_saved_object_conflict_message.tsx +++ /dev/null @@ -1,19 +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 type { SavedObjectConflictMessageProps } from '../types'; - -export const getSavedObjectConflictMessage = async (): Promise< - React.FC -> => { - const { SavedObjectConflictMessage } = await import('./saved_object_conflict_message'); - return (props: SavedObjectConflictMessageProps) => { - return ; - }; -}; diff --git a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/index.ts b/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/index.ts index fa641d03fd7153..f692715789680b 100644 --- a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/index.ts +++ b/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/index.ts @@ -6,5 +6,3 @@ */ export { getShareToSpaceFlyoutComponent } from './share_to_space_flyout'; -export { getSavedObjectConflictMessage } from './get_saved_object_conflict_message'; -export { getLegacyUrlConflict } from './legacy_url_conflict'; diff --git a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/legacy_url_conflict_internal.tsx b/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/legacy_url_conflict_internal.tsx deleted file mode 100644 index 95bf7b404db346..00000000000000 --- a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/legacy_url_conflict_internal.tsx +++ /dev/null @@ -1,116 +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 { - EuiButton, - EuiButtonEmpty, - EuiCallOut, - EuiFlexGroup, - EuiFlexItem, - EuiSpacer, -} from '@elastic/eui'; -import React, { useEffect, useState } from 'react'; -import { first } from 'rxjs/operators'; - -import { FormattedMessage } from '@kbn/i18n/react'; -import type { ApplicationStart, StartServicesAccessor } from 'src/core/public'; - -import type { PluginsStart } from '../../plugin'; -import type { LegacyUrlConflictProps } from '../types'; -import { DEFAULT_OBJECT_NOUN } from './constants'; - -export interface InternalProps { - getStartServices: StartServicesAccessor; -} - -export const LegacyUrlConflictInternal = (props: InternalProps & LegacyUrlConflictProps) => { - const { - getStartServices, - objectNoun = DEFAULT_OBJECT_NOUN, - currentObjectId, - otherObjectId, - otherObjectPath, - } = props; - - const [applicationStart, setApplicationStart] = useState(); - const [isDismissed, setIsDismissed] = useState(false); - const [appId, setAppId] = useState(); - - useEffect(() => { - async function setup() { - const [{ application }] = await getStartServices(); - const appIdValue = await application.currentAppId$.pipe(first()).toPromise(); // retrieve the most recent value from the BehaviorSubject - setApplicationStart(application); - setAppId(appIdValue); - } - setup(); - }, [getStartServices]); - - if (!applicationStart || !appId || isDismissed) { - return null; - } - - function clickLinkButton() { - applicationStart!.navigateToApp(appId!, { path: otherObjectPath }); - } - - function clickDismissButton() { - setIsDismissed(true); - } - - return ( - - } - > - - - - - - - - - - - - - - - - - - - ); -}; diff --git a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/saved_object_conflict_message.tsx b/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/saved_object_conflict_message.tsx deleted file mode 100644 index 22a1ad7cd20aae..00000000000000 --- a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/saved_object_conflict_message.tsx +++ /dev/null @@ -1,56 +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 { EuiButtonEmpty, EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui'; -import React, { useState } from 'react'; - -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; - -import type { SavedObjectConflictMessageProps } from '../types'; - -export const SavedObjectConflictMessage = ({ json }: SavedObjectConflictMessageProps) => { - const [expandError, setExpandError] = useState(false); - return ( - <> - - {i18n.translate('xpack.spaces.legacyURLConflict.documentationLinkText', { - defaultMessage: 'legacy URL alias', - })} - - ), - }} - /> - - {expandError ? ( - - ) : ( - setExpandError(true)}> - {i18n.translate('xpack.spaces.legacyURLConflict.expandError', { - defaultMessage: `Show more`, - })} - - )} - - ); -}; diff --git a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/selectable_spaces_control.tsx b/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/selectable_spaces_control.tsx index 3b7569d7c36da9..9ba2e41098fdb5 100644 --- a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/selectable_spaces_control.tsx +++ b/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/selectable_spaces_control.tsx @@ -26,7 +26,6 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { SPACE_SEARCH_COUNT_THRESHOLD } from '../../../common'; import { ALL_SPACES_ID, UNKNOWN_SPACE } from '../../../common/constants'; -import { DocumentationLinksService } from '../../lib'; import { getSpaceAvatarComponent } from '../../space_avatar'; import { useSpaces } from '../../spaces_context'; import type { SpacesDataEntry } from '../../types'; @@ -135,9 +134,7 @@ export const SelectableSpacesControl = (props: Props) => { return null; } - const kibanaPrivilegesUrl = new DocumentationLinksService( - docLinks! - ).getKibanaPrivilegesDocUrl(); + const docLink = docLinks?.links.security.kibanaPrivileges; return ( @@ -146,7 +143,7 @@ export const SelectableSpacesControl = (props: Props) => { defaultMessage="To view hidden spaces, you need {additionalPrivilegesLink}." values={{ additionalPrivilegesLink: ( - + { return null; } - const kibanaPrivilegesUrl = new DocumentationLinksService( - docLinks! - ).getKibanaPrivilegesDocUrl(); - + const docLink = docLinks?.links.security.kibanaPrivileges; return ( <> { values={{ objectNoun, readAndWritePrivilegesLink: ( - + + getEmbeddableLegacyUrlConflict({ spacesManager, getStartServices }) + ), getLegacyUrlConflict: wrapLazy(() => getLegacyUrlConflict({ getStartServices })), getSpaceAvatar: wrapLazy(getSpaceAvatarComponent), - getSavedObjectConflictMessage: wrapLazy(() => getSavedObjectConflictMessage()), }; }; diff --git a/x-pack/plugins/spaces/public/ui_api/index.ts b/x-pack/plugins/spaces/public/ui_api/index.ts index e0749b04de139f..a8c77dce6fdff0 100644 --- a/x-pack/plugins/spaces/public/ui_api/index.ts +++ b/x-pack/plugins/spaces/public/ui_api/index.ts @@ -7,8 +7,8 @@ import type { StartServicesAccessor } from 'src/core/public'; +import { createRedirectLegacyUrl } from '../legacy_urls'; import type { PluginsStart } from '../plugin'; -import { createRedirectLegacyUrl } from '../share_saved_objects_to_space'; import { useSpaces } from '../spaces_context'; import type { SpacesManager } from '../spaces_manager'; import { getComponents } from './components'; diff --git a/x-pack/plugins/spaces/public/ui_api/types.ts b/x-pack/plugins/spaces/public/ui_api/types.ts index 67e43f0cd31a6c..eb2aefd5dd534b 100644 --- a/x-pack/plugins/spaces/public/ui_api/types.ts +++ b/x-pack/plugins/spaces/public/ui_api/types.ts @@ -10,11 +10,8 @@ import type { ReactElement } from 'react'; import type { CoreStart } from 'src/core/public'; import type { CopyToSpaceFlyoutProps } from '../copy_saved_objects_to_space'; -import type { - LegacyUrlConflictProps, - SavedObjectConflictMessageProps, - ShareToSpaceFlyoutProps, -} from '../share_saved_objects_to_space'; +import type { EmbeddableLegacyUrlConflictProps, LegacyUrlConflictProps } from '../legacy_urls'; +import type { ShareToSpaceFlyoutProps } from '../share_saved_objects_to_space'; import type { SpaceAvatarProps } from '../space_avatar'; import type { SpaceListProps } from '../space_list'; import type { SpacesContextProps, SpacesReactContextValue } from '../spaces_context'; @@ -88,6 +85,12 @@ export interface SpacesApiUiComponent { * Note: must be rendered inside of a SpacesContext. */ getSpaceList: LazyComponentFn; + /** + * Displays a callout that needs to be used if an embeddable component call to `SavedObjectsClient.resolve()` results in an `"conflict"` + * outcome, which indicates that the user has loaded an embeddable which is associated directly with one object (A), *and* with a legacy + * URL that points to a different object (B). + */ + getEmbeddableLegacyUrlConflict: LazyComponentFn; /** * Displays a callout that needs to be used if a call to `SavedObjectsClient.resolve()` results in an `"conflict"` outcome, which * indicates that the user has loaded the page which is associated directly with one object (A), *and* with a legacy URL that points to a @@ -110,8 +113,4 @@ export interface SpacesApiUiComponent { * Displays an avatar for the given space. */ getSpaceAvatar: LazyComponentFn; - /** - * Displays a saved object conflict message that directs user to disable legacy URL alias - */ - getSavedObjectConflictMessage: LazyComponentFn; } diff --git a/x-pack/plugins/timelines/common/search_strategy/index_fields/index.ts b/x-pack/plugins/timelines/common/search_strategy/index_fields/index.ts index 8fbab31b492666..d207cf21fcb362 100644 --- a/x-pack/plugins/timelines/common/search_strategy/index_fields/index.ts +++ b/x-pack/plugins/timelines/common/search_strategy/index_fields/index.ts @@ -67,12 +67,7 @@ export interface BrowserField { name: string; searchable: boolean; type: string; - subType?: { - [key: string]: unknown; - nested?: { - path: string; - }; - }; + subType?: IFieldSubType; } export type BrowserFields = Readonly>>; diff --git a/x-pack/plugins/timelines/common/types/timeline/index.ts b/x-pack/plugins/timelines/common/types/timeline/index.ts index 5ceeebca878c7b..c57f247493ffce 100644 --- a/x-pack/plugins/timelines/common/types/timeline/index.ts +++ b/x-pack/plugins/timelines/common/types/timeline/index.ts @@ -468,7 +468,7 @@ export enum TimelineTabs { } // eslint-disable-next-line @typescript-eslint/no-explicit-any -type EmptyObject = Record; +type EmptyObject = Partial>; export type TimelineExpandedEventType = | { @@ -512,9 +512,9 @@ export type TimelineExpandedDetailType = | TimelineExpandedHostType | TimelineExpandedNetworkType; -export type TimelineExpandedDetail = { - [tab in TimelineTabs]?: TimelineExpandedDetailType; -}; +export type TimelineExpandedDetail = Partial< + Record +>; export type ToggleDetailPanel = TimelineExpandedDetailType & { tabType?: TimelineTabs; diff --git a/x-pack/plugins/timelines/public/store/t_grid/helpers.ts b/x-pack/plugins/timelines/public/store/t_grid/helpers.ts index 730d127d16d98a..f7b0d86f88621c 100644 --- a/x-pack/plugins/timelines/public/store/t_grid/helpers.ts +++ b/x-pack/plugins/timelines/public/store/t_grid/helpers.ts @@ -16,6 +16,8 @@ import type { ColumnHeaderOptions, DataProvider, SortColumnTimeline, + TimelineExpandedDetail, + TimelineExpandedDetailType, } from '../../../common/types/timeline'; import { getTGridManageDefaults, tGridDefaults } from './defaults'; @@ -412,22 +414,20 @@ export const setSelectedTimelineEvents = ({ }; }; -export const updateTimelineDetailsPanel = (action: ToggleDetailPanel) => { - const { tabType } = action; +export const updateTimelineDetailsPanel = (action: ToggleDetailPanel): TimelineExpandedDetail => { + const { tabType, timelineId, ...expandedDetails } = action; const panelViewOptions = new Set(['eventDetail', 'hostDetail', 'networkDetail']); const expandedTabType = tabType ?? TimelineTabs.query; - - return action.panelView && panelViewOptions.has(action.panelView) - ? { - [expandedTabType]: { - params: action.params ? { ...action.params } : {}, - panelView: action.panelView, - }, - } - : { - [expandedTabType]: {}, - }; + const newExpandDetails = { + params: expandedDetails.params ? { ...expandedDetails.params } : {}, + panelView: expandedDetails.panelView, + } as TimelineExpandedDetailType; + return { + [expandedTabType]: panelViewOptions.has(expandedDetails.panelView ?? '') + ? newExpandDetails + : {}, + }; }; export const addProviderToTimelineHelper = ( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx index 8c96aae2e0dae5..bccd3aff72c582 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx @@ -20,7 +20,8 @@ jest.mock('../../../../../app/app_dependencies'); import { MlSharedContext } from '../../../../../app/__mocks__/shared_context'; import { getMlSharedImports } from '../../../../../shared_imports'; -describe('Transform: Transform List ', () => { +// FLAKY https://github.com/elastic/kibana/issues/112922 +describe.skip('Transform: Transform List ', () => { // Set timezone to US/Eastern for consistent test results. beforeEach(() => { moment.tz.setDefault('US/Eastern'); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index a05d38795cf764..f36f3abe66a4ca 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -238,6 +238,8 @@ "xpack.lens.editorFrame.expressionMissingDatasource": "ビジュアライゼーションのデータソースが見つかりませんでした", "xpack.lens.editorFrame.expressionMissingVisualizationType": "ビジュアライゼーションタイプが見つかりません。", "xpack.lens.editorFrame.goToForums": "リクエストとフィードバック", + "xpack.lens.editorFrame.indexPatternNotFound": "インデックスパターンが見つかりませんでした", + "xpack.lens.editorFrame.indexPatternReconfigure": "インデックスパターン管理ページで再作成", "xpack.lens.editorFrame.invisibleIndicatorLabel": "このディメンションは現在グラフに表示されません", "xpack.lens.editorFrame.networkErrorMessage": "ネットワークエラーです。しばらくたってから再試行するか、管理者に連絡してください。", "xpack.lens.editorFrame.noColorIndicatorLabel": "このディメンションには個別の色がありません", @@ -364,6 +366,7 @@ "xpack.lens.indexPattern.cardinality": "ユニークカウント", "xpack.lens.indexPattern.cardinality.signature": "フィールド:文字列", "xpack.lens.indexPattern.cardinalityOf": "{name} のユニークカウント", + "xpack.lens.indexPattern.changeIndexPatternTitle": "インデックスパターン", "xpack.lens.indexPattern.chooseField": "フィールドを選択", "xpack.lens.indexPattern.chooseFieldLabel": "この関数を使用するには、フィールドを選択してください。", "xpack.lens.indexPattern.chooseSubFunction": "サブ関数を選択", @@ -403,6 +406,7 @@ "xpack.lens.indexPattern.derivative": "差異", "xpack.lens.indexPattern.derivativeOf": "{name} の差異", "xpack.lens.indexPattern.differences.signature": "メトリック:数値", + "xpack.lens.indexPattern.editFieldLabel": "インデックスパターンフィールドを編集", "xpack.lens.indexPattern.emptyDimensionButton": "空のディメンション", "xpack.lens.indexPattern.emptyFieldsLabel": "空のフィールド", "xpack.lens.indexPattern.emptyFieldsLabelHelp": "空のフィールドには、フィルターに基づく最初の 500 件のドキュメントの値が含まれていませんでした。", @@ -463,12 +467,15 @@ "xpack.lens.indexPattern.functionsLabel": "関数を選択", "xpack.lens.indexPattern.groupByDropdown": "グループ分けの条件", "xpack.lens.indexPattern.incompleteOperation": "(未完了)", + "xpack.lens.indexPattern.indexPatternLoadError": "インデックスパターンの読み込み中にエラーが発生", "xpack.lens.indexPattern.intervals": "間隔", + "xpack.lens.indexPattern.invalidFieldLabel": "無効なフィールドです。インデックスパターンを確認するか、別のフィールドを選択してください。", "xpack.lens.indexPattern.invalidInterval": "無効な間隔値", "xpack.lens.indexPattern.invalidOperationLabel": "選択した関数はこのフィールドで動作しません。", "xpack.lens.indexPattern.invalidReferenceConfiguration": "ディメンション\"{dimensionLabel}\"の構成が正しくありません", "xpack.lens.indexPattern.invalidTimeShift": "無効な時間シフトです。正の整数の後に単位s、m、h、d、w、M、yのいずれかを入力します。例:3時間は3hです", "xpack.lens.indexPattern.lastValue": "最終値", + "xpack.lens.indexPattern.lastValue.disabled": "この関数には、インデックスの日付フィールドが必要です", "xpack.lens.indexPattern.lastValue.invalidTypeSortField": "フィールド {invalidField} は日付フィールドではないため、並べ替えで使用できません", "xpack.lens.indexPattern.lastValue.signature": "フィールド:文字列", "xpack.lens.indexPattern.lastValue.sortField": "日付フィールドで並べ替え", @@ -504,6 +511,8 @@ "xpack.lens.indexPattern.movingAverage.windowLimitations": "ウィンドウには現在の値が含まれません。", "xpack.lens.indexPattern.movingAverageOf": "{name} の移動平均", "xpack.lens.indexPattern.multipleDateHistogramsError": "\"{dimensionLabel}\"は唯一の日付ヒストグラムではありません。時間シフトを使用するときには、1つの日付ヒストグラムのみを使用していることを確認してください。", + "xpack.lens.indexPattern.noPatternsDescription": "インデックスパターンを作成するか、別のデータソースに切り替えてください", + "xpack.lens.indexPattern.noPatternsLabel": "インデックスパターンがありません", "xpack.lens.indexPattern.numberFormatLabel": "数字", "xpack.lens.indexPattern.ofDocumentsLabel": "ドキュメント", "xpack.lens.indexPattern.otherDocsLabel": "その他", @@ -547,6 +556,7 @@ "xpack.lens.indexPattern.referenceFunctionPlaceholder": "サブ関数", "xpack.lens.indexPattern.removeColumnAriaLabel": "フィールドを追加するか、{groupLabel}までドラッグアンドドロップします", "xpack.lens.indexPattern.removeColumnLabel": "「{groupLabel}」から構成を削除", + "xpack.lens.indexPattern.removeFieldLabel": "インデックスパターンを削除", "xpack.lens.indexPattern.sortField.invalid": "無効なフィールドです。インデックスパターンを確認するか、別のフィールドを選択してください。", "xpack.lens.indexpattern.suggestions.nestingChangeLabel": "各 {outerOperation} の {innerOperation}", "xpack.lens.indexpattern.suggestions.overallLabel": "全体の {operation}", @@ -592,8 +602,12 @@ "xpack.lens.indexPattern.timeShiftSmallWarning": "{label}は{columnTimeShift}の時間シフトを使用しています。これは{interval}の日付ヒストグラム間隔よりも小さいです。不一致のデータを防止するには、時間シフトとして{interval}を使用します。", "xpack.lens.indexPattern.uniqueLabel": "{label} [{num}]", "xpack.lens.indexPattern.useAsTopLevelAgg": "最初にこのフィールドでグループ化", + "xpack.lens.indexPatterns.actionsPopoverLabel": "インデックスパターン設定", + "xpack.lens.indexPatterns.addFieldButton": "フィールドをインデックスパターンに追加", "xpack.lens.indexPatterns.clearFiltersLabel": "名前とタイプフィルターを消去", "xpack.lens.indexPatterns.fieldFiltersLabel": "タイプでフィルタリング", + "xpack.lens.indexPatterns.filterByNameLabel": "検索フィールド名", + "xpack.lens.indexPatterns.manageFieldButton": "インデックスパターンを管理", "xpack.lens.indexPatterns.noAvailableDataLabel": "データを含むフィールドはありません。", "xpack.lens.indexPatterns.noDataLabel": "フィールドがありません。", "xpack.lens.indexPatterns.noEmptyDataLabel": "空のフィールドがありません。", @@ -601,12 +615,14 @@ "xpack.lens.indexPatterns.noFields.fieldTypeFilterBullet": "別のフィールドフィルターを使用", "xpack.lens.indexPatterns.noFields.globalFiltersBullet": "グローバルフィルターを変更", "xpack.lens.indexPatterns.noFields.tryText": "試行対象:", + "xpack.lens.indexPatterns.noFieldsLabel": "このインデックスパターンにはフィールドがありません。", "xpack.lens.indexPatterns.noFilteredFieldsLabel": "選択したフィルターと一致するフィールドはありません。", "xpack.lens.indexPatterns.noMetaDataLabel": "メタフィールドがありません。", "xpack.lens.indexPatternSuggestion.removeLayerLabel": "{indexPatternTitle}のみを表示", "xpack.lens.indexPatternSuggestion.removeLayerPositionLabel": "レイヤー{layerNumber}のみを表示", "xpack.lens.labelInput.label": "ラベル", "xpack.lens.layerPanel.layerVisualizationType": "レイヤービジュアライゼーションタイプ", + "xpack.lens.layerPanel.missingIndexPattern": "インデックスパターンが見つかりませんでした", "xpack.lens.lensSavedObjectLabel": "レンズビジュアライゼーション", "xpack.lens.metric.addLayer": "ビジュアライゼーションレイヤーを追加", "xpack.lens.metric.groupLabel": "表形式の値と単一の値", @@ -4455,11 +4471,6 @@ "savedObjectsManagement.view.indexPatternDoesNotExistErrorMessage": "このオブジェクトに関連付けられたインデックスパターンは現在存在しません。", "savedObjectsManagement.view.savedObjectProblemErrorMessage": "この保存されたオブジェクトに問題があります", "savedObjectsManagement.view.savedSearchDoesNotExistErrorMessage": "このオブジェクトに関連付けられた保存された検索は現在存在しません。", - "security.checkup.dismissButtonText": "閉じる", - "security.checkup.dontShowAgain": "今後表示しない", - "security.checkup.insecureClusterMessage": "1 ビットを失わないでください。Elastic では無料でデータを保護できます。", - "security.checkup.insecureClusterTitle": "データが保護されていません", - "security.checkup.learnMoreButtonText": "詳細", "share.advancedSettings.csv.quoteValuesText": "csvエクスポートに値を引用するかどうかです", "share.advancedSettings.csv.quoteValuesTitle": "CSVの値を引用", "share.advancedSettings.csv.separatorText": "エクスポートされた値をこの文字列で区切ります", @@ -4902,21 +4913,21 @@ "visTypeMetric.colorModes.backgroundOptionLabel": "背景", "visTypeMetric.colorModes.labelsOptionLabel": "ラベル", "visTypeMetric.colorModes.noneOptionLabel": "なし", - "visTypeMetric.function.adimension.splitGroup": "グループを分割", - "visTypeMetric.function.bgFill.help": "html 16 進数コード(#123456)、html 色(red、blue)、または rgba 値(rgba(255,255,255,1))。", - "visTypeMetric.function.bucket.help": "バケットディメンションの構成です。", - "visTypeMetric.function.colorMode.help": "色を変更するメトリックの部分", - "visTypeMetric.function.colorRange.help": "別の色が適用される値のグループを指定する範囲オブジェクト。", - "visTypeMetric.function.colorSchema.help": "使用する配色", - "visTypeMetric.function.dimension.metric": "メトリック", - "visTypeMetric.function.font.help": "フォント設定です。", - "visTypeMetric.function.help": "メトリックビジュアライゼーション", - "visTypeMetric.function.invertColors.help": "色範囲を反転します", - "visTypeMetric.function.metric.help": "メトリックディメンションの構成です。", - "visTypeMetric.function.percentageMode.help": "百分率モードでメトリックを表示します。colorRange を設定する必要があります。", - "visTypeMetric.function.showLabels.help": "メトリック値の下にラベルを表示します。", - "visTypeMetric.function.subText.help": "メトリックの下に表示するカスタムテキスト", - "visTypeMetric.function.useRanges.help": "有効な色範囲です。", + "expressionMetricVis.function.dimension.splitGroup": "グループを分割", + "expressionMetricVis.function.bgFill.help": "html 16 進数コード(#123456)、html 色(red、blue)、または rgba 値(rgba(255,255,255,1))。", + "expressionMetricVis.function.bucket.help": "バケットディメンションの構成です。", + "expressionMetricVis.function.colorMode.help": "色を変更するメトリックの部分", + "expressionMetricVis.function.colorRange.help": "別の色が適用される値のグループを指定する範囲オブジェクト。", + "expressionMetricVis.function.colorSchema.help": "使用する配色", + "expressionMetricVis.function.dimension.metric": "メトリック", + "expressionMetricVis.function.font.help": "フォント設定です。", + "expressionMetricVis.function.help": "メトリックビジュアライゼーション", + "expressionMetricVis.function.invertColors.help": "色範囲を反転します", + "expressionMetricVis.function.metric.help": "メトリックディメンションの構成です。", + "expressionMetricVis.function.percentageMode.help": "百分率モードでメトリックを表示します。colorRange を設定する必要があります。", + "expressionMetricVis.function.showLabels.help": "メトリック値の下にラベルを表示します。", + "expressionMetricVis.function.subText.help": "メトリックの下に表示するカスタムテキスト", + "expressionMetricVis.function.useRanges.help": "有効な色範囲です。", "visTypeMetric.metricDescription": "計算結果を単独の数字として表示します。", "visTypeMetric.metricTitle": "メトリック", "visTypeMetric.params.color.useForLabel": "使用する色", @@ -5198,6 +5209,12 @@ "visTypeTimeseries.indexPattern.timeRange.lastValue": "最終値", "visTypeTimeseries.indexPattern.timeRange.selectTimeRange": "選択してください", "visTypeTimeseries.indexPattern.сoarse": "粗い", + "visTypeTimeseries.indexPatternSelect.createIndexPatternText": "インデックスパターンを作成", + "visTypeTimeseries.indexPatternSelect.defaultIndexPatternText": "デフォルトのインデックスパターンが使用されています。", + "visTypeTimeseries.indexPatternSelect.label": "インデックスパターン", + "visTypeTimeseries.indexPatternSelect.queryAllIndexesText": "すべてのインデックスにクエリを実行するには * を使用します", + "visTypeTimeseries.indexPatternSelect.switchModePopover.areaLabel": "インデックスパターン選択モードを構成", + "visTypeTimeseries.indexPatternSelect.switchModePopover.title": "インデックスパターン選択モード", "visTypeTimeseries.kbnVisTypes.metricsDescription": "時系列データの高度な分析を実行します。", "visTypeTimeseries.kbnVisTypes.metricsTitle": "TSVB", "visTypeTimeseries.lastValueModeIndicator.lastBucketDate": "バケット:{lastBucketDate}", @@ -5326,6 +5343,7 @@ "visTypeTimeseries.seriesConfig.ignoreGlobalFilterLabel": "グローバルフィルターを無視しますか?", "visTypeTimeseries.seriesConfig.missingSeriesComponentDescription": "パネルタイプ {panelType} の数列コンポーネントが欠けています", "visTypeTimeseries.seriesConfig.offsetSeriesTimeLabel": "数列の時間を(1m, 1h, 1w, 1d)でオフセット", + "visTypeTimeseries.seriesConfig.overrideIndexPatternLabel": "インデックスパターンを上書きしますか?", "visTypeTimeseries.seriesConfig.templateHelpText": "eg. {templateExample}", "visTypeTimeseries.seriesConfig.templateLabel": "テンプレート", "visTypeTimeseries.sort.dragToSortAriaLabel": "ドラッグして並べ替えます", @@ -5456,6 +5474,7 @@ "visTypeTimeseries.timeseries.optionsTab.styleLabel": "スタイル", "visTypeTimeseries.timeseries.optionsTab.tooltipMode": "ツールチップ", "visTypeTimeseries.timeseries.optionsTab.truncateLegendLabel": "凡例を切り捨てますか?", + "visTypeTimeseries.timeSeries.overrideIndexPatternLabel": "インデックスパターンを上書きしますか?", "visTypeTimeseries.timeSeries.percentLabel": "パーセント", "visTypeTimeseries.timeseries.positionOptions.leftLabel": "左", "visTypeTimeseries.timeseries.positionOptions.rightLabel": "右", @@ -5520,8 +5539,9 @@ "visTypeTimeseries.visEditorVisualization.changesHaveNotBeenAppliedMessage": "ビジュアライゼーションへの変更が適用されました。", "visTypeTimeseries.visEditorVisualization.changesSuccessfullyAppliedMessage": "最新の変更が適用されました。", "visTypeTimeseries.visEditorVisualization.changesWillBeAutomaticallyAppliedMessage": "変更が自動的に適用されます。", - "visTypeTimeseries.visEditorVisualization.dataViewMode.dismissNoticeButtonText": "閉じる", - "visTypeTimeseries.visEditorVisualization.dataViewMode.link": "確認してください。", + "visTypeTimeseries.visEditorVisualization.indexPatternMode.dismissNoticeButtonText": "閉じる", + "visTypeTimeseries.visEditorVisualization.indexPatternMode.link": "確認してください。", + "visTypeTimeseries.visEditorVisualization.indexPatternMode.notificationTitle": "TSVBはインデックスパターンをサポートします", "visTypeTimeseries.visPicker.gaugeLabel": "ゲージ", "visTypeTimeseries.visPicker.metricLabel": "メトリック", "visTypeTimeseries.visPicker.tableLabel": "表", @@ -5895,6 +5915,7 @@ "visualizations.newVisWizard.newVisTypeTitle": "新規 {visTypeName}", "visualizations.newVisWizard.readDocumentationLink": "ドキュメンテーションを表示", "visualizations.newVisWizard.searchSelection.notFoundLabel": "一致インデックスまたは保存した検索が見つかりません。", + "visualizations.newVisWizard.searchSelection.savedObjectType.indexPattern": "インデックスパターン", "visualizations.newVisWizard.searchSelection.savedObjectType.search": "保存検索", "visualizations.newVisWizard.title": "新規ビジュアライゼーション", "visualizations.newVisWizard.toolsGroupTitle": "ツール", @@ -9315,7 +9336,6 @@ "xpack.enterpriseSearch.appSearch.engine.curations.empty.buttonLabel": "キュレーションガイドを読む", "xpack.enterpriseSearch.appSearch.engine.curations.empty.description": "キュレーションを使用して、ドキュメントを昇格させるか非表示にします。最も検出させたい内容をユーザーに検出させるように支援します。", "xpack.enterpriseSearch.appSearch.engine.curations.empty.noCurationsTitle": "最初のキュレーションを作成", - "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.description": "非表示のドキュメントはオーガニック結果に表示されません。", "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.emptyDescription": "上記のオーガニック結果の目アイコンをクリックしてドキュメントを非表示にするか、結果を手動で検索して非表示にします。", "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.emptyTitle": "まだドキュメントを非表示にしていません", "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.removeAllButtonLabel": "すべて復元", @@ -24189,10 +24209,6 @@ "xpack.spaces.shareToSpace.currentSpaceBadge": "現在", "xpack.spaces.shareToSpace.featureIsDisabledTooltip": "この機能はこのスペースでは無効です。", "xpack.spaces.shareToSpace.flyoutTitle": "{objectNoun}をスペースに割り当てる", - "xpack.spaces.shareToSpace.legacyUrlConflictBody": "現在、{objectNoun} [id={currentObjectId}]を表示しています。このページのレガシーURLは別の{objectNoun} [id={otherObjectId}]を示しています。", - "xpack.spaces.shareToSpace.legacyUrlConflictDismissButton": "閉じる", - "xpack.spaces.shareToSpace.legacyUrlConflictLinkButton": "他の{objectNoun}に移動", - "xpack.spaces.shareToSpace.legacyUrlConflictTitle": "2つのオブジェクトがこのURLに関連付けられています", "xpack.spaces.shareToSpace.noAvailableSpaces.canCreateNewSpace.linkText": "新しいスペースを作成", "xpack.spaces.shareToSpace.noAvailableSpaces.canCreateNewSpace.text": "オブジェクトを共有するには、{createANewSpaceLink}できます。", "xpack.spaces.shareToSpace.objectNoun": "オブジェクト", @@ -24201,8 +24217,6 @@ "xpack.spaces.shareToSpace.privilegeWarningBody": "この{objectNoun}のスペースを編集するには、すべてのスペースで{readAndWritePrivilegesLink}が必要です。", "xpack.spaces.shareToSpace.privilegeWarningLink": "読み書き権限", "xpack.spaces.shareToSpace.privilegeWarningTitle": "追加の権限が必要です", - "xpack.spaces.shareToSpace.redirectLegacyUrlToast.text": "検索している{objectNoun}は新しい場所にあります。今後はこのURLを使用してください。", - "xpack.spaces.shareToSpace.redirectLegacyUrlToast.title": "新しいURLに移動しました", "xpack.spaces.shareToSpace.saveButton": "保存して閉じる", "xpack.spaces.shareToSpace.shareErrorTitle": "{objectNoun}の更新エラー", "xpack.spaces.shareToSpace.shareModeControl.buttonGroupLegend": "この共有方法を選択", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 9d3b54723a442e..11b951b97ae050 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -241,8 +241,11 @@ "xpack.lens.editorFrame.expressionFailureMessage": "请求错误:{type},{reason}", "xpack.lens.editorFrame.expressionFailureMessageWithContext": "请求错误:{type},{context} 中的 {reason}", "xpack.lens.editorFrame.expressionMissingDatasource": "无法找到可视化的数据源", + "xpack.lens.editorFrame.expressionMissingIndexPattern": "找不到{count, plural, other {索引模式}}:{ids}", "xpack.lens.editorFrame.expressionMissingVisualizationType": "找不到可视化类型。", "xpack.lens.editorFrame.goToForums": "提出请求并提供反馈", + "xpack.lens.editorFrame.indexPatternNotFound": "未找到索引模式", + "xpack.lens.editorFrame.indexPatternReconfigure": "在索引模式管理页面中重新创建", "xpack.lens.editorFrame.invisibleIndicatorLabel": "此维度当前在图表中不可见", "xpack.lens.editorFrame.networkErrorMessage": "网络错误,请稍后重试或联系管理员。", "xpack.lens.editorFrame.noColorIndicatorLabel": "此维度没有单独的颜色", @@ -371,6 +374,7 @@ "xpack.lens.indexPattern.cardinality": "唯一计数", "xpack.lens.indexPattern.cardinality.signature": "field: string", "xpack.lens.indexPattern.cardinalityOf": "{name} 的唯一计数", + "xpack.lens.indexPattern.changeIndexPatternTitle": "索引模式", "xpack.lens.indexPattern.chooseField": "选择字段", "xpack.lens.indexPattern.chooseFieldLabel": "要使用此函数,请选择字段。", "xpack.lens.indexPattern.chooseSubFunction": "选择子函数", @@ -410,6 +414,7 @@ "xpack.lens.indexPattern.derivative": "差异", "xpack.lens.indexPattern.derivativeOf": "{name} 的差异", "xpack.lens.indexPattern.differences.signature": "指标:数字", + "xpack.lens.indexPattern.editFieldLabel": "编辑索引模式字段", "xpack.lens.indexPattern.emptyDimensionButton": "空维度", "xpack.lens.indexPattern.emptyFieldsLabel": "空字段", "xpack.lens.indexPattern.emptyFieldsLabelHelp": "空字段在基于您的筛选的前 500 个文档中不包含任何值。", @@ -471,12 +476,15 @@ "xpack.lens.indexPattern.functionsLabel": "选择函数", "xpack.lens.indexPattern.groupByDropdown": "分组依据", "xpack.lens.indexPattern.incompleteOperation": "(不完整)", + "xpack.lens.indexPattern.indexPatternLoadError": "加载索引模式时出错", "xpack.lens.indexPattern.intervals": "时间间隔", + "xpack.lens.indexPattern.invalidFieldLabel": "字段无效。检查索引模式或选取其他字段。", "xpack.lens.indexPattern.invalidInterval": "时间间隔值无效", "xpack.lens.indexPattern.invalidOperationLabel": "此字段不适用于选定函数。", "xpack.lens.indexPattern.invalidReferenceConfiguration": "维度“{dimensionLabel}”配置不正确", "xpack.lens.indexPattern.invalidTimeShift": "时间偏移无效。输入正整数数量,后跟以下单位之一:s、m、h、d、w、M、y。例如,3h 表示 3 小时", "xpack.lens.indexPattern.lastValue": "最后值", + "xpack.lens.indexPattern.lastValue.disabled": "此功能要求索引中存在日期字段", "xpack.lens.indexPattern.lastValue.invalidTypeSortField": "字段 {invalidField} 不是日期字段,不能用于排序", "xpack.lens.indexPattern.lastValue.signature": "field: string", "xpack.lens.indexPattern.lastValue.sortField": "按日期字段排序", @@ -496,6 +504,7 @@ "xpack.lens.indexPattern.min.description": "单值指标聚合,返回从聚合文档提取的数值中的最小值。", "xpack.lens.indexPattern.minOf": "{name} 的最小值", "xpack.lens.indexPattern.missingFieldLabel": "缺失字段", + "xpack.lens.indexPattern.missingIndexPattern": "找不到{count, plural, other {索引模式}} ({count, plural, other {id}}:{indexpatterns})", "xpack.lens.indexPattern.missingReferenceError": "“{dimensionLabel}”配置不完整", "xpack.lens.indexPattern.moveToWorkspace": "将 {field} 添加到工作区", "xpack.lens.indexPattern.moveToWorkspaceDisabled": "此字段无法自动添加到工作区。您仍可以在配置面板中直接使用它。", @@ -512,6 +521,8 @@ "xpack.lens.indexPattern.movingAverage.windowLimitations": "时间窗不包括当前值。", "xpack.lens.indexPattern.movingAverageOf": "{name} 的移动平均值", "xpack.lens.indexPattern.multipleDateHistogramsError": "“{dimensionLabel}”不是唯一的 Date Histogram。使用时间偏移时,请确保仅使用一个 Date Histogram。", + "xpack.lens.indexPattern.noPatternsDescription": "请创建索引模式或切换到其他数据源", + "xpack.lens.indexPattern.noPatternsLabel": "无索引模式", "xpack.lens.indexPattern.numberFormatLabel": "数字", "xpack.lens.indexPattern.ofDocumentsLabel": "文档", "xpack.lens.indexPattern.operationsNotFound": "未找到{operationLength, plural, other {运算}} {operationsList}", @@ -556,6 +567,7 @@ "xpack.lens.indexPattern.referenceFunctionPlaceholder": "子函数", "xpack.lens.indexPattern.removeColumnAriaLabel": "将字段添加或拖放到 {groupLabel}", "xpack.lens.indexPattern.removeColumnLabel": "从“{groupLabel}”中删除配置", + "xpack.lens.indexPattern.removeFieldLabel": "移除索引模式字段", "xpack.lens.indexPattern.sortField.invalid": "字段无效。检查索引模式或选取其他字段。", "xpack.lens.indexpattern.suggestions.nestingChangeLabel": "每个 {outerOperation} 的 {innerOperation}", "xpack.lens.indexpattern.suggestions.overallLabel": "总体 {operation}", @@ -601,9 +613,13 @@ "xpack.lens.indexPattern.timeShiftSmallWarning": "{label} 使用的时间偏移 {columnTimeShift} 小于 Date Histogram 时间间隔 {interval} 。要防止数据不匹配,请使用 {interval} 的倍数作为时间偏移。", "xpack.lens.indexPattern.uniqueLabel": "{label} [{num}]", "xpack.lens.indexPattern.useAsTopLevelAgg": "先按此字段分组", + "xpack.lens.indexPatterns.actionsPopoverLabel": "索引模式设置", + "xpack.lens.indexPatterns.addFieldButton": "将字段添加到索引模式", "xpack.lens.indexPatterns.clearFiltersLabel": "清除名称和类型筛选", "xpack.lens.indexPatterns.fieldFiltersLabel": "按类型筛选", "xpack.lens.indexPatterns.fieldSearchLiveRegion": "{availableFields} 个可用{availableFields, plural, other {字段}}。{emptyFields} 个空{emptyFields, plural, other {字段}}。{metaFields} 个元{metaFields, plural,other {字段}}。", + "xpack.lens.indexPatterns.filterByNameLabel": "搜索字段名称", + "xpack.lens.indexPatterns.manageFieldButton": "管理索引模式字段", "xpack.lens.indexPatterns.noAvailableDataLabel": "没有包含数据的可用字段。", "xpack.lens.indexPatterns.noDataLabel": "无字段。", "xpack.lens.indexPatterns.noEmptyDataLabel": "无空字段。", @@ -611,12 +627,14 @@ "xpack.lens.indexPatterns.noFields.fieldTypeFilterBullet": "使用不同的字段筛选", "xpack.lens.indexPatterns.noFields.globalFiltersBullet": "更改全局筛选", "xpack.lens.indexPatterns.noFields.tryText": "尝试:", + "xpack.lens.indexPatterns.noFieldsLabel": "在此索引模式中不存在任何字段。", "xpack.lens.indexPatterns.noFilteredFieldsLabel": "没有字段匹配选定筛选。", "xpack.lens.indexPatterns.noMetaDataLabel": "无元字段。", "xpack.lens.indexPatternSuggestion.removeLayerLabel": "仅显示 {indexPatternTitle}", "xpack.lens.indexPatternSuggestion.removeLayerPositionLabel": "仅显示图层 {layerNumber}", "xpack.lens.labelInput.label": "标签", "xpack.lens.layerPanel.layerVisualizationType": "图层可视化类型", + "xpack.lens.layerPanel.missingIndexPattern": "未找到索引模式", "xpack.lens.lensSavedObjectLabel": "Lens 可视化", "xpack.lens.metric.addLayer": "添加可视化图层", "xpack.lens.metric.groupLabel": "表和单值", @@ -4498,11 +4516,6 @@ "savedObjectsManagement.view.indexPatternDoesNotExistErrorMessage": "与此对象关联的索引模式已不存在。", "savedObjectsManagement.view.savedObjectProblemErrorMessage": "此已保存对象有问题", "savedObjectsManagement.view.savedSearchDoesNotExistErrorMessage": "与此对象关联的已保存搜索已不存在。", - "security.checkup.dismissButtonText": "关闭", - "security.checkup.dontShowAgain": "不再显示", - "security.checkup.insecureClusterMessage": "不要丢失一位。使用 Elastic,免费保护您的数据。", - "security.checkup.insecureClusterTitle": "您的数据并非安全无忧", - "security.checkup.learnMoreButtonText": "了解详情", "share.advancedSettings.csv.quoteValuesText": "在 CSV 导出中是否应使用引号引起值?", "share.advancedSettings.csv.quoteValuesTitle": "使用引号引起 CSV 值", "share.advancedSettings.csv.separatorText": "使用此字符串分隔导出的值", @@ -4945,21 +4958,21 @@ "visTypeMetric.colorModes.backgroundOptionLabel": "背景", "visTypeMetric.colorModes.labelsOptionLabel": "标签", "visTypeMetric.colorModes.noneOptionLabel": "无", - "visTypeMetric.function.adimension.splitGroup": "拆分组", - "visTypeMetric.function.bgFill.help": "将颜色表示为 html 十六进制代码 (#123456)、html 颜色(red、blue)或 rgba 值 (rgba(255,255,255,1))。", - "visTypeMetric.function.bucket.help": "存储桶维度配置", - "visTypeMetric.function.colorMode.help": "指标的哪部分要上色", - "visTypeMetric.function.colorRange.help": "指定应将不同颜色应用到的值组的范围对象。", - "visTypeMetric.function.colorSchema.help": "要使用的颜色方案", - "visTypeMetric.function.dimension.metric": "指标", - "visTypeMetric.function.font.help": "字体设置。", - "visTypeMetric.function.help": "指标可视化", - "visTypeMetric.function.invertColors.help": "反转颜色范围", - "visTypeMetric.function.metric.help": "指标维度配置", - "visTypeMetric.function.percentageMode.help": "以百分比模式显示指标。需要设置 colorRange。", - "visTypeMetric.function.showLabels.help": "在指标值下显示标签。", - "visTypeMetric.function.subText.help": "要在指标下显示的定制文本", - "visTypeMetric.function.useRanges.help": "已启用颜色范围。", + "expressionMetricVis.function.dimension.splitGroup": "拆分组", + "expressionMetricVis.function.bgFill.help": "将颜色表示为 html 十六进制代码 (#123456)、html 颜色(red、blue)或 rgba 值 (rgba(255,255,255,1))。", + "expressionMetricVis.function.bucket.help": "存储桶维度配置", + "expressionMetricVis.function.colorMode.help": "指标的哪部分要上色", + "expressionMetricVis.function.colorRange.help": "指定应将不同颜色应用到的值组的范围对象。", + "expressionMetricVis.function.colorSchema.help": "要使用的颜色方案", + "expressionMetricVis.function.dimension.metric": "指标", + "expressionMetricVis.function.font.help": "字体设置。", + "expressionMetricVis.function.help": "指标可视化", + "expressionMetricVis.function.invertColors.help": "反转颜色范围", + "expressionMetricVis.function.metric.help": "指标维度配置", + "expressionMetricVis.function.percentageMode.help": "以百分比模式显示指标。需要设置 colorRange。", + "expressionMetricVis.function.showLabels.help": "在指标值下显示标签。", + "expressionMetricVis.function.subText.help": "要在指标下显示的定制文本", + "expressionMetricVis.function.useRanges.help": "已启用颜色范围。", "visTypeMetric.metricDescription": "将计算结果显示为单个数字。", "visTypeMetric.metricTitle": "指标", "visTypeMetric.params.color.useForLabel": "将颜色用于", @@ -5241,6 +5254,12 @@ "visTypeTimeseries.indexPattern.timeRange.lastValue": "最后值", "visTypeTimeseries.indexPattern.timeRange.selectTimeRange": "选择", "visTypeTimeseries.indexPattern.сoarse": "粗糙", + "visTypeTimeseries.indexPatternSelect.createIndexPatternText": "创建索引模式", + "visTypeTimeseries.indexPatternSelect.defaultIndexPatternText": "将使用默认索引模式。", + "visTypeTimeseries.indexPatternSelect.label": "索引模式", + "visTypeTimeseries.indexPatternSelect.queryAllIndexesText": "要查询所有索引,请使用 *", + "visTypeTimeseries.indexPatternSelect.switchModePopover.areaLabel": "配置索引模式选择模式", + "visTypeTimeseries.indexPatternSelect.switchModePopover.title": "索引模式选择模式", "visTypeTimeseries.kbnVisTypes.metricsDescription": "对时间序列数据执行高级分析。", "visTypeTimeseries.kbnVisTypes.metricsTitle": "TSVB", "visTypeTimeseries.lastValueModeIndicator.lastBucketDate": "存储桶:{lastBucketDate}", @@ -5370,6 +5389,7 @@ "visTypeTimeseries.seriesConfig.ignoreGlobalFilterLabel": "忽略全局筛选?", "visTypeTimeseries.seriesConfig.missingSeriesComponentDescription": "以下面板类型缺失序列组件:{panelType}", "visTypeTimeseries.seriesConfig.offsetSeriesTimeLabel": "将序列时间偏移(1m、1h、1w、1d)", + "visTypeTimeseries.seriesConfig.overrideIndexPatternLabel": "覆盖索引模式?", "visTypeTimeseries.seriesConfig.templateHelpText": "例如 {templateExample}", "visTypeTimeseries.seriesConfig.templateLabel": "模板", "visTypeTimeseries.sort.dragToSortAriaLabel": "拖动以排序", @@ -5500,6 +5520,7 @@ "visTypeTimeseries.timeseries.optionsTab.styleLabel": "样式", "visTypeTimeseries.timeseries.optionsTab.tooltipMode": "工具提示", "visTypeTimeseries.timeseries.optionsTab.truncateLegendLabel": "截断图例?", + "visTypeTimeseries.timeSeries.overrideIndexPatternLabel": "覆盖索引模式?", "visTypeTimeseries.timeSeries.percentLabel": "百分比", "visTypeTimeseries.timeseries.positionOptions.leftLabel": "左", "visTypeTimeseries.timeseries.positionOptions.rightLabel": "右", @@ -5564,8 +5585,9 @@ "visTypeTimeseries.visEditorVisualization.changesHaveNotBeenAppliedMessage": "尚未应用对此可视化的更改。", "visTypeTimeseries.visEditorVisualization.changesSuccessfullyAppliedMessage": "已应用最新更改。", "visTypeTimeseries.visEditorVisualization.changesWillBeAutomaticallyAppliedMessage": "将自动应用更改。", - "visTypeTimeseries.visEditorVisualization.dataViewMode.dismissNoticeButtonText": "关闭", - "visTypeTimeseries.visEditorVisualization.dataViewMode.link": "请查看。", + "visTypeTimeseries.visEditorVisualization.indexPatternMode.dismissNoticeButtonText": "关闭", + "visTypeTimeseries.visEditorVisualization.indexPatternMode.link": "请查看。", + "visTypeTimeseries.visEditorVisualization.indexPatternMode.notificationTitle": "TSVB 现在支持索引模式", "visTypeTimeseries.visPicker.gaugeLabel": "仪表盘", "visTypeTimeseries.visPicker.metricLabel": "指标", "visTypeTimeseries.visPicker.tableLabel": "表", @@ -5940,6 +5962,7 @@ "visualizations.newVisWizard.readDocumentationLink": "阅读文档", "visualizations.newVisWizard.resultsFound": "{resultCount, plural, other {类型}}已找到", "visualizations.newVisWizard.searchSelection.notFoundLabel": "未找到匹配的索引或已保存搜索。", + "visualizations.newVisWizard.searchSelection.savedObjectType.indexPattern": "索引模式", "visualizations.newVisWizard.searchSelection.savedObjectType.search": "已保存搜索", "visualizations.newVisWizard.title": "新建可视化", "visualizations.newVisWizard.toolsGroupTitle": "工具", @@ -9407,7 +9430,6 @@ "xpack.enterpriseSearch.appSearch.engine.curations.empty.buttonLabel": "阅读策展指南", "xpack.enterpriseSearch.appSearch.engine.curations.empty.description": "使用策展提升和隐藏文档。帮助人们发现最想让他们发现的内容。", "xpack.enterpriseSearch.appSearch.engine.curations.empty.noCurationsTitle": "创建您的首个策展", - "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.description": "隐藏的文档将不显示在有机结果中。", "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.emptyDescription": "通过单击上面有机结果上的眼睛图标,可隐藏文档,或手动搜索和隐藏结果。", "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.emptyTitle": "您尚未隐藏任何文档", "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.removeAllButtonLabel": "全部还原", @@ -24592,10 +24614,6 @@ "xpack.spaces.shareToSpace.currentSpaceBadge": "当前", "xpack.spaces.shareToSpace.featureIsDisabledTooltip": "此功能在此工作区中已禁用。", "xpack.spaces.shareToSpace.flyoutTitle": "将 {objectNoun} 分配给工作区", - "xpack.spaces.shareToSpace.legacyUrlConflictBody": "当前您正在查看 {objectNoun} [id={currentObjectId}]。此页面的旧 URL 显示不同的 {objectNoun} [id={otherObjectId}]。", - "xpack.spaces.shareToSpace.legacyUrlConflictDismissButton": "关闭", - "xpack.spaces.shareToSpace.legacyUrlConflictLinkButton": "前往其他 {objectNoun}", - "xpack.spaces.shareToSpace.legacyUrlConflictTitle": "2 个对象与此 URL 关联", "xpack.spaces.shareToSpace.noAvailableSpaces.canCreateNewSpace.linkText": "创建新工作区", "xpack.spaces.shareToSpace.noAvailableSpaces.canCreateNewSpace.text": "您可以{createANewSpaceLink},用于共享您的对象。", "xpack.spaces.shareToSpace.objectNoun": "对象", @@ -24604,8 +24622,6 @@ "xpack.spaces.shareToSpace.privilegeWarningBody": "要编辑此 {objectNoun} 的工作区,您在所有工作区中都需要{readAndWritePrivilegesLink}。", "xpack.spaces.shareToSpace.privilegeWarningLink": "读写权限", "xpack.spaces.shareToSpace.privilegeWarningTitle": "需要其他权限", - "xpack.spaces.shareToSpace.redirectLegacyUrlToast.text": "您正在寻找的{objectNoun}具有新的位置。从现在开始使用此 URL。", - "xpack.spaces.shareToSpace.redirectLegacyUrlToast.title": "我们已将您重定向到新 URL", "xpack.spaces.shareToSpace.relativesControl.description": "{relativesCount} 个相关{relativesCount, plural, other {对象}}也将更改。", "xpack.spaces.shareToSpace.saveButton": "保存并关闭", "xpack.spaces.shareToSpace.shareErrorTitle": "更新 {objectNoun} 时出错", diff --git a/x-pack/plugins/uptime/public/hooks/__snapshots__/use_url_params.test.tsx.snap b/x-pack/plugins/uptime/public/hooks/__snapshots__/use_url_params.test.tsx.snap index d8b148675dc62b..5bac7ff7caf766 100644 --- a/x-pack/plugins/uptime/public/hooks/__snapshots__/use_url_params.test.tsx.snap +++ b/x-pack/plugins/uptime/public/hooks/__snapshots__/use_url_params.test.tsx.snap @@ -197,7 +197,7 @@ exports[`useUrlParams deletes keys that do not have truthy values 1`] = ` }, ], }, - Symbol(observable): [MockFunction], + "undefined": [MockFunction], } } > @@ -427,7 +427,7 @@ exports[`useUrlParams gets the expected values using the context 1`] = ` }, ], }, - Symbol(observable): [MockFunction], + "undefined": [MockFunction], } } > diff --git a/x-pack/plugins/watcher/__jest__/client_integration/helpers/app_context.mock.tsx b/x-pack/plugins/watcher/__jest__/client_integration/helpers/app_context.mock.tsx index 01c7155832745f..8176d3fcbbca27 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/helpers/app_context.mock.tsx +++ b/x-pack/plugins/watcher/__jest__/client_integration/helpers/app_context.mock.tsx @@ -9,6 +9,7 @@ import React from 'react'; import { of } from 'rxjs'; import { ComponentType } from 'enzyme'; import { LocationDescriptorObject } from 'history'; + import { docLinksServiceMock, uiSettingsServiceMock, @@ -17,6 +18,7 @@ import { scopedHistoryMock, } from '../../../../../../src/core/public/mocks'; import { AppContextProvider } from '../../../public/application/app_context'; +import { AppDeps } from '../../../public/application/app'; import { LicenseStatus } from '../../../common/types/license_status'; class MockTimeBuckets { @@ -35,7 +37,7 @@ history.createHref.mockImplementation((location: LocationDescriptorObject) => { return `${location.pathname}${location.search ? '?' + location.search : ''}`; }); -export const mockContextValue = { +export const mockContextValue: AppDeps = { licenseStatus$: of({ valid: true }), docLinks: docLinksServiceMock.createStartContract(), setBreadcrumbs: jest.fn(), diff --git a/x-pack/plugins/watcher/__jest__/client_integration/helpers/index.ts b/x-pack/plugins/watcher/__jest__/client_integration/helpers/index.ts index 961e2a458dc0ca..09a841ff147a49 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/helpers/index.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/helpers/index.ts @@ -11,7 +11,7 @@ import { setup as watchCreateJsonSetup } from './watch_create_json.helpers'; import { setup as watchCreateThresholdSetup } from './watch_create_threshold.helpers'; import { setup as watchEditSetup } from './watch_edit.helpers'; -export { nextTick, getRandomString, findTestSubject, TestBed } from '@kbn/test/jest'; +export { getRandomString, findTestSubject, TestBed } from '@kbn/test/jest'; export { wrapBodyResponse, unwrapBodyResponse } from './body_response'; export { setupEnvironment } from './setup_environment'; diff --git a/x-pack/plugins/watcher/__jest__/client_integration/helpers/setup_environment.ts b/x-pack/plugins/watcher/__jest__/client_integration/helpers/setup_environment.ts index 05b325ee946bda..5ba0387d21ba79 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/helpers/setup_environment.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/helpers/setup_environment.ts @@ -7,6 +7,7 @@ import axios from 'axios'; import axiosXhrAdapter from 'axios/lib/adapters/xhr'; + import { init as initHttpRequests } from './http_requests'; import { setHttpClient, setSavedObjectsClient } from '../../../public/application/lib/api'; diff --git a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_create_threshold.helpers.ts b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_create_threshold.helpers.ts index c70684b80a6d59..caddf1df93d405 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_create_threshold.helpers.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_create_threshold.helpers.ts @@ -93,7 +93,7 @@ export type TestSubjects = | 'toEmailAddressInput' | 'triggerIntervalSizeInput' | 'watchActionAccordion' - | 'watchActionAccordion.mockComboBox' + | 'watchActionAccordion.toEmailAddressInput' | 'watchActionsPanel' | 'watchThresholdButton' | 'watchThresholdInput' diff --git a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_list.helpers.ts b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_list.helpers.ts index ad171f9e40cad1..c0643e70dded9c 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_list.helpers.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_list.helpers.ts @@ -7,7 +7,7 @@ import { act } from 'react-dom/test-utils'; -import { registerTestBed, findTestSubject, TestBed, TestBedConfig, nextTick } from '@kbn/test/jest'; +import { registerTestBed, findTestSubject, TestBed, TestBedConfig } from '@kbn/test/jest'; import { WatchList } from '../../../public/application/sections/watch_list/components/watch_list'; import { ROUTES, REFRESH_INTERVALS } from '../../../common/constants'; import { withAppContext } from './app_context.mock'; @@ -24,7 +24,6 @@ const initTestBed = registerTestBed(withAppContext(WatchList), testBedConfig); export interface WatchListTestBed extends TestBed { actions: { selectWatchAt: (index: number) => void; - clickWatchAt: (index: number) => void; clickWatchActionAt: (index: number, action: 'delete' | 'edit') => void; searchWatches: (term: string) => void; advanceTimeToTableRefresh: () => Promise; @@ -45,18 +44,6 @@ export const setup = async (): Promise => { checkBox.simulate('change', { target: { checked: true } }); }; - const clickWatchAt = async (index: number) => { - const { rows } = testBed.table.getMetaData('watchesTable'); - const watchesLink = findTestSubject(rows[index].reactWrapper, 'watchesLink'); - - await act(async () => { - const { href } = watchesLink.props(); - testBed.router.navigateTo(href!); - await nextTick(); - testBed.component.update(); - }); - }; - const clickWatchActionAt = async (index: number, action: 'delete' | 'edit') => { const { component, table } = testBed; const { rows } = table.getMetaData('watchesTable'); @@ -95,7 +82,6 @@ export const setup = async (): Promise => { ...testBed, actions: { selectWatchAt, - clickWatchAt, clickWatchActionAt, searchWatches, advanceTimeToTableRefresh, diff --git a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_status.helpers.ts b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_status.helpers.ts index a1c7e8b4049973..02b6908fc1d4c9 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_status.helpers.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_status.helpers.ts @@ -7,7 +7,7 @@ import { act } from 'react-dom/test-utils'; -import { registerTestBed, findTestSubject, TestBed, TestBedConfig, delay } from '@kbn/test/jest'; +import { registerTestBed, findTestSubject, TestBed, TestBedConfig } from '@kbn/test/jest'; import { WatchStatus } from '../../../public/application/sections/watch_status/components/watch_status'; import { ROUTES } from '../../../common/constants'; import { WATCH_ID } from './jest_constants'; @@ -89,9 +89,8 @@ export const setup = async (): Promise => { await act(async () => { button.simulate('click'); - await delay(100); - component.update(); }); + component.update(); }; return { diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts index 4a632d9752cacd..f9ea51a80ae763 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json.test.ts @@ -9,7 +9,7 @@ import { act } from 'react-dom/test-utils'; import { getExecuteDetails } from '../../__fixtures__'; import { defaultWatch } from '../../public/application/models/watch'; -import { setupEnvironment, pageHelpers, nextTick, wrapBodyResponse } from './helpers'; +import { setupEnvironment, pageHelpers, wrapBodyResponse } from './helpers'; import { WatchCreateJsonTestBed } from './helpers/watch_create_json.helpers'; import { WATCH } from './helpers/jest_constants'; @@ -19,19 +19,19 @@ describe(' create route', () => { const { server, httpRequestsMockHelpers } = setupEnvironment(); let testBed: WatchCreateJsonTestBed; + beforeAll(() => { + jest.useFakeTimers(); + }); + afterAll(() => { + jest.useRealTimers(); server.restore(); }); describe('on component mount', () => { beforeEach(async () => { testBed = await setup(); - - await act(async () => { - const { component } = testBed; - await nextTick(); - component.update(); - }); + testBed.component.update(); }); test('should set the correct page title', () => { @@ -92,7 +92,6 @@ describe(' create route', () => { await act(async () => { actions.clickSubmitButton(); - await nextTick(); }); const latestRequest = server.requests[server.requests.length - 1]; @@ -141,9 +140,8 @@ describe(' create route', () => { await act(async () => { actions.clickSubmitButton(); - await nextTick(); - component.update(); }); + component.update(); expect(exists('sectionError')).toBe(true); expect(find('sectionError').text()).toContain(error.message); @@ -169,7 +167,6 @@ describe(' create route', () => { await act(async () => { actions.clickSimulateButton(); - await nextTick(); }); const latestRequest = server.requests[server.requests.length - 1]; @@ -230,9 +227,8 @@ describe(' create route', () => { await act(async () => { actions.clickSimulateButton(); - await nextTick(); - component.update(); }); + component.update(); const latestRequest = server.requests[server.requests.length - 1]; diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx index 77e65dfd91c75d..481f59093d7dc2 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx @@ -9,15 +9,10 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import axiosXhrAdapter from 'axios/lib/adapters/xhr'; import axios from 'axios'; + import { getExecuteDetails } from '../../__fixtures__'; import { WATCH_TYPES } from '../../common/constants'; -import { - setupEnvironment, - pageHelpers, - nextTick, - wrapBodyResponse, - unwrapBodyResponse, -} from './helpers'; +import { setupEnvironment, pageHelpers, wrapBodyResponse, unwrapBodyResponse } from './helpers'; import { WatchCreateThresholdTestBed } from './helpers/watch_create_threshold.helpers'; const WATCH_NAME = 'my_test_watch'; @@ -76,7 +71,9 @@ jest.mock('@elastic/eui', () => { // which does not produce a valid component wrapper EuiComboBox: (props: any) => ( { props.onChange([syntheticEvent['0']]); }} @@ -91,7 +88,12 @@ describe(' create route', () => { const { server, httpRequestsMockHelpers } = setupEnvironment(); let testBed: WatchCreateThresholdTestBed; + beforeAll(() => { + jest.useFakeTimers(); + }); + afterAll(() => { + jest.useRealTimers(); server.restore(); }); @@ -99,7 +101,6 @@ describe(' create route', () => { beforeEach(async () => { testBed = await setup(); const { component } = testBed; - await nextTick(); component.update(); }); @@ -159,46 +160,60 @@ describe(' create route', () => { test('it should enable the Create button and render additional content with valid fields', async () => { const { form, find, component, exists } = testBed; - form.setInputValue('nameInput', 'my_test_watch'); - find('mockComboBox').simulate('change', [{ label: 'index1', value: 'index1' }]); // Using mocked EuiComboBox - form.setInputValue('watchTimeFieldSelect', '@timestamp'); + expect(find('saveWatchButton').props().disabled).toBe(true); await act(async () => { - await nextTick(); - component.update(); + form.setInputValue('nameInput', 'my_test_watch'); + find('indicesComboBox').simulate('change', [{ label: 'index1', value: 'index1' }]); // Using mocked EuiComboBox + form.setInputValue('watchTimeFieldSelect', '@timestamp'); }); + component.update(); - expect(find('saveWatchButton').props().disabled).toEqual(false); - + expect(find('saveWatchButton').props().disabled).toBe(false); expect(find('watchConditionTitle').text()).toBe('Match the following condition'); expect(exists('watchVisualizationChart')).toBe(true); expect(exists('watchActionsPanel')).toBe(true); }); - // Looks like there is an issue with using 'mockComboBox'. - describe.skip('watch conditions', () => { - beforeEach(() => { - const { form, find } = testBed; + describe('watch conditions', () => { + beforeEach(async () => { + const { form, find, component } = testBed; // Name, index and time fields are required before the watch condition expression renders - form.setInputValue('nameInput', 'my_test_watch'); - act(() => { - find('mockComboBox').simulate('change', [{ label: 'index1', value: 'index1' }]); // Using mocked EuiComboBox + await act(async () => { + form.setInputValue('nameInput', 'my_test_watch'); + find('indicesComboBox').simulate('change', [{ label: 'index1', value: 'index1' }]); // Using mocked EuiComboBox + form.setInputValue('watchTimeFieldSelect', '@timestamp'); }); - form.setInputValue('watchTimeFieldSelect', '@timestamp'); + component.update(); }); - test('should require a threshold value', () => { - const { form, find } = testBed; + test('should require a threshold value', async () => { + const { form, find, component } = testBed; + // Display the threshold pannel act(() => { find('watchThresholdButton').simulate('click'); + }); + component.update(); + + await act(async () => { // Provide invalid value form.setInputValue('watchThresholdInput', ''); + }); + + // We need to wait for the debounced validation to be triggered and update the DOM + jest.advanceTimersByTime(500); + component.update(); + + expect(form.getErrorsMessages()).toContain('A value is required.'); + + await act(async () => { // Provide valid value form.setInputValue('watchThresholdInput', '0'); }); - expect(form.getErrorsMessages()).toContain('A value is required.'); + component.update(); + // No need to wait as the validation errors are cleared whenever the field changes expect(form.getErrorsMessages().length).toEqual(0); }); }); @@ -209,14 +224,12 @@ describe(' create route', () => { const { form, find, component } = testBed; // Set up valid fields needed for actions component to render - form.setInputValue('nameInput', WATCH_NAME); - find('mockComboBox').simulate('change', [{ label: 'index1', value: 'index1' }]); // Using mocked EuiComboBox - form.setInputValue('watchTimeFieldSelect', WATCH_TIME_FIELD); - await act(async () => { - await nextTick(); - component.update(); + form.setInputValue('nameInput', WATCH_NAME); + find('indicesComboBox').simulate('change', [{ label: 'index1', value: 'index1' }]); + form.setInputValue('watchTimeFieldSelect', WATCH_TIME_FIELD); }); + component.update(); }); test('should simulate a logging action', async () => { @@ -240,7 +253,6 @@ describe(' create route', () => { await act(async () => { actions.clickSimulateButton(); - await nextTick(); }); // Verify request @@ -303,7 +315,6 @@ describe(' create route', () => { await act(async () => { actions.clickSimulateButton(); - await nextTick(); }); // Verify request @@ -366,7 +377,6 @@ describe(' create route', () => { await act(async () => { actions.clickSimulateButton(); - await nextTick(); }); // Verify request @@ -431,15 +441,14 @@ describe(' create route', () => { expect(exists('watchActionAccordion')).toBe(true); // Provide valid fields and verify - find('watchActionAccordion.mockComboBox').simulate('change', [ + find('watchActionAccordion.toEmailAddressInput').simulate('change', [ { label: EMAIL_RECIPIENT, value: EMAIL_RECIPIENT }, - ]); // Using mocked EuiComboBox + ]); form.setInputValue('emailSubjectInput', EMAIL_SUBJECT); form.setInputValue('emailBodyInput', EMAIL_BODY); await act(async () => { actions.clickSimulateButton(); - await nextTick(); }); // Verify request @@ -532,7 +541,6 @@ describe(' create route', () => { await act(async () => { actions.clickSimulateButton(); - await nextTick(); }); // Verify request @@ -621,7 +629,6 @@ describe(' create route', () => { await act(async () => { actions.clickSimulateButton(); - await nextTick(); }); // Verify request @@ -702,7 +709,6 @@ describe(' create route', () => { await act(async () => { actions.clickSimulateButton(); - await nextTick(); }); // Verify request @@ -753,20 +759,66 @@ describe(' create route', () => { }); }); + describe('watch visualize data payload', () => { + test('should send the correct payload', async () => { + const { form, find, component } = testBed; + + // Set up required fields + await act(async () => { + form.setInputValue('nameInput', WATCH_NAME); + find('indicesComboBox').simulate('change', [{ label: 'index1', value: 'index1' }]); + form.setInputValue('watchTimeFieldSelect', WATCH_TIME_FIELD); + }); + component.update(); + + const latestReqToGetVisualizeData = server.requests.find( + (req) => req.method === 'POST' && req.url === '/api/watcher/watch/visualize' + ); + if (!latestReqToGetVisualizeData) { + throw new Error(`No request found to fetch visualize data.`); + } + + const requestBody = unwrapBodyResponse(latestReqToGetVisualizeData.requestBody); + + expect(requestBody.watch).toEqual({ + id: requestBody.watch.id, // id is dynamic + name: 'my_test_watch', + type: 'threshold', + isNew: true, + isActive: true, + actions: [], + index: ['index1'], + timeField: '@timestamp', + triggerIntervalSize: 1, + triggerIntervalUnit: 'm', + aggType: 'count', + termSize: 5, + termOrder: 'desc', + thresholdComparator: '>', + timeWindowSize: 5, + timeWindowUnit: 'm', + hasTermsAgg: false, + threshold: 1000, + }); + + expect(requestBody.options.interval).toBeDefined(); + }); + }); + describe('form payload', () => { test('should send the correct payload', async () => { const { form, find, component, actions } = testBed; // Set up required fields - form.setInputValue('nameInput', WATCH_NAME); - find('mockComboBox').simulate('change', [{ label: 'index1', value: 'index1' }]); // Using mocked EuiComboBox - form.setInputValue('watchTimeFieldSelect', WATCH_TIME_FIELD); + await act(async () => { + form.setInputValue('nameInput', WATCH_NAME); + find('indicesComboBox').simulate('change', [{ label: 'index1', value: 'index1' }]); + form.setInputValue('watchTimeFieldSelect', WATCH_TIME_FIELD); + }); + component.update(); await act(async () => { - await nextTick(); - component.update(); actions.clickSubmitButton(); - await nextTick(); }); // Verify request diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts index e8782edc829a46..1188cc8469a58d 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts @@ -12,7 +12,7 @@ import { getRandomString } from '@kbn/test/jest'; import { getWatch } from '../../__fixtures__'; import { defaultWatch } from '../../public/application/models/watch'; -import { setupEnvironment, pageHelpers, nextTick, wrapBodyResponse } from './helpers'; +import { setupEnvironment, pageHelpers, wrapBodyResponse } from './helpers'; import { WatchEditTestBed } from './helpers/watch_edit.helpers'; import { WATCH } from './helpers/jest_constants'; @@ -41,7 +41,12 @@ describe('', () => { const { server, httpRequestsMockHelpers } = setupEnvironment(); let testBed: WatchEditTestBed; + beforeAll(() => { + jest.useFakeTimers(); + }); + afterAll(() => { + jest.useRealTimers(); server.restore(); }); @@ -50,11 +55,7 @@ describe('', () => { httpRequestsMockHelpers.setLoadWatchResponse(WATCH); testBed = await setup(); - - await act(async () => { - await nextTick(); - testBed.component.update(); - }); + testBed.component.update(); }); describe('on component mount', () => { @@ -87,7 +88,6 @@ describe('', () => { await act(async () => { actions.clickSubmitButton(); - await nextTick(); }); const latestRequest = server.requests[server.requests.length - 1]; @@ -141,12 +141,7 @@ describe('', () => { httpRequestsMockHelpers.setLoadWatchResponse({ watch }); testBed = await setup(); - - await act(async () => { - const { component } = testBed; - await nextTick(); - component.update(); - }); + testBed.component.update(); }); describe('on component mount', () => { @@ -172,7 +167,6 @@ describe('', () => { await act(async () => { actions.clickSubmitButton(); - await nextTick(); }); const latestRequest = server.requests[server.requests.length - 1]; diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_status.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_status.test.ts index c19ec62b94477b..1b1b813617da6c 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_status.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_status.test.ts @@ -9,7 +9,7 @@ import { act } from 'react-dom/test-utils'; import moment from 'moment'; import { getWatchHistory } from '../../__fixtures__'; import { ROUTES, WATCH_STATES, ACTION_STATES } from '../../common/constants'; -import { setupEnvironment, pageHelpers, nextTick } from './helpers'; +import { setupEnvironment, pageHelpers } from './helpers'; import { WatchStatusTestBed } from './helpers/watch_status.helpers'; import { WATCH } from './helpers/jest_constants'; @@ -43,7 +43,12 @@ describe('', () => { const { server, httpRequestsMockHelpers } = setupEnvironment(); let testBed: WatchStatusTestBed; + beforeAll(() => { + jest.useFakeTimers(); + }); + afterAll(() => { + jest.useRealTimers(); server.restore(); }); @@ -53,11 +58,7 @@ describe('', () => { httpRequestsMockHelpers.setLoadWatchHistoryResponse(watchHistoryItems); testBed = await setup(); - - await act(async () => { - await nextTick(); - testBed.component.update(); - }); + testBed.component.update(); }); test('should set the correct page title', () => { @@ -175,9 +176,8 @@ describe('', () => { await act(async () => { confirmButton!.click(); - await nextTick(); - component.update(); }); + component.update(); const latestRequest = server.requests[server.requests.length - 1]; diff --git a/x-pack/plugins/watcher/public/plugin.ts b/x-pack/plugins/watcher/public/plugin.ts index 6c6d6f1169658e..093f34e70400fe 100644 --- a/x-pack/plugins/watcher/public/plugin.ts +++ b/x-pack/plugins/watcher/public/plugin.ts @@ -8,13 +8,11 @@ import { i18n } from '@kbn/i18n'; import { CoreSetup, Plugin, CoreStart, Capabilities } from 'kibana/public'; import { first, map, skip } from 'rxjs/operators'; - import { Subject, combineLatest } from 'rxjs'; -import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public'; - -import { LicenseStatus } from '../common/types/license_status'; +import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public'; import { ILicense } from '../../licensing/public'; +import { LicenseStatus } from '../common/types/license_status'; import { PLUGIN } from '../common/constants'; import { Dependencies } from './types'; diff --git a/x-pack/plugins/watcher/server/models/watch/lib/get_interval_type/get_interval_type.test.ts b/x-pack/plugins/watcher/server/models/watch/lib/get_interval_type/get_interval_type.test.ts new file mode 100644 index 00000000000000..a90876d1baf2ef --- /dev/null +++ b/x-pack/plugins/watcher/server/models/watch/lib/get_interval_type/get_interval_type.test.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getIntervalType } from './get_interval_type'; + +describe('get interval type', () => { + test('should detect fixed intervals', () => { + ['1ms', '1s', '1m', '1h', '1d', '21s', '7d'].forEach((interval) => { + const intervalDetected = getIntervalType(interval); + try { + expect(intervalDetected).toBe('fixed_interval'); + } catch (e) { + throw new Error( + `Expected [${interval}] to be a fixed interval but got [${intervalDetected}]` + ); + } + }); + }); + + test('should detect calendar intervals', () => { + ['1w', '1M', '1q', '1y'].forEach((interval) => { + const intervalDetected = getIntervalType(interval); + try { + expect(intervalDetected).toBe('calendar_interval'); + } catch (e) { + throw new Error( + `Expected [${interval}] to be a calendar interval but got [${intervalDetected}]` + ); + } + }); + }); +}); diff --git a/x-pack/plugins/watcher/server/models/watch/lib/get_interval_type/get_interval_type.ts b/x-pack/plugins/watcher/server/models/watch/lib/get_interval_type/get_interval_type.ts new file mode 100644 index 00000000000000..5e23523a133c40 --- /dev/null +++ b/x-pack/plugins/watcher/server/models/watch/lib/get_interval_type/get_interval_type.ts @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/** + * Since 8.x we use the "fixed_interval" or "calendar_interval" parameter instead + * of the less precise "interval". This helper parse the interval and return its type. + * @param interval Interval value (e.g. "1d", "1w"...) + */ +export const getIntervalType = (interval: string): 'fixed_interval' | 'calendar_interval' => { + // We will consider all interval as fixed except if they are + // weekly (w), monthly (M), quarterly (q) or yearly (y) + const intervalMetric = interval.charAt(interval.length - 1); + if (['w', 'M', 'q', 'y'].includes(intervalMetric)) { + return 'calendar_interval'; + } + return 'fixed_interval'; +}; diff --git a/x-pack/plugins/watcher/server/models/watch/lib/get_interval_type/index.ts b/x-pack/plugins/watcher/server/models/watch/lib/get_interval_type/index.ts new file mode 100644 index 00000000000000..0bb505e4ea7222 --- /dev/null +++ b/x-pack/plugins/watcher/server/models/watch/lib/get_interval_type/index.ts @@ -0,0 +1,8 @@ +/* + * 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 { getIntervalType } from './get_interval_type'; diff --git a/x-pack/plugins/watcher/server/models/watch/threshold_watch/build_visualize_query.js b/x-pack/plugins/watcher/server/models/watch/threshold_watch/build_visualize_query.js index 10ba68c3193a06..60b2dd5a546bef 100644 --- a/x-pack/plugins/watcher/server/models/watch/threshold_watch/build_visualize_query.js +++ b/x-pack/plugins/watcher/server/models/watch/threshold_watch/build_visualize_query.js @@ -6,8 +6,10 @@ */ import { cloneDeep } from 'lodash'; + import { buildInput } from '../../../../common/lib/serialization'; import { AGG_TYPES } from '../../../../common/constants'; +import { getIntervalType } from '../lib/get_interval_type'; /* input.search.request.body.query.bool.filter.range @@ -22,17 +24,6 @@ function buildRange({ rangeFrom, rangeTo, timeField }) { }; } -function buildDateAgg({ field, interval, timeZone }) { - return { - date_histogram: { - field, - interval, - time_zone: timeZone, - min_doc_count: 1, - }, - }; -} - function buildAggsCount(body, dateAgg) { return { dateAgg, @@ -93,7 +84,7 @@ function buildAggs(body, { aggType, termField }, dateAgg) { } } -export function buildVisualizeQuery(watch, visualizeOptions) { +export function buildVisualizeQuery(watch, visualizeOptions, kibanaVersion) { const { index, timeWindowSize, @@ -117,11 +108,22 @@ export function buildVisualizeQuery(watch, visualizeOptions) { termOrder, }); const body = watchInput.search.request.body; - const dateAgg = buildDateAgg({ - field: watch.timeField, - interval: visualizeOptions.interval, - timeZone: visualizeOptions.timezone, - }); + const dateAgg = { + date_histogram: { + field: watch.timeField, + time_zone: visualizeOptions.timezone, + min_doc_count: 1, + }, + }; + + if (kibanaVersion.major < 8) { + // In 7.x we use the deprecated "interval" in date_histogram agg + dateAgg.date_histogram.interval = visualizeOptions.interval; + } else { + // From 8.x we use the more precise "fixed_interval" or "calendar_interval" + const intervalType = getIntervalType(visualizeOptions.interval); + dateAgg.date_histogram[intervalType] = visualizeOptions.interval; + } // override the query range body.query.bool.filter.range = buildRange({ diff --git a/x-pack/plugins/watcher/server/models/watch/threshold_watch/threshold_watch.js b/x-pack/plugins/watcher/server/models/watch/threshold_watch/threshold_watch.js index 5cc8a5535c8c31..a20b83e83e3b70 100644 --- a/x-pack/plugins/watcher/server/models/watch/threshold_watch/threshold_watch.js +++ b/x-pack/plugins/watcher/server/models/watch/threshold_watch/threshold_watch.js @@ -48,8 +48,8 @@ export class ThresholdWatch extends BaseWatch { return serializeThresholdWatch(this); } - getVisualizeQuery(visualizeOptions) { - return buildVisualizeQuery(this, visualizeOptions); + getVisualizeQuery(visualizeOptions, kibanaVersion) { + return buildVisualizeQuery(this, visualizeOptions, kibanaVersion); } formatVisualizeData(results) { diff --git a/x-pack/plugins/watcher/server/plugin.ts b/x-pack/plugins/watcher/server/plugin.ts index aea8368c7bbedd..52d77520183abe 100644 --- a/x-pack/plugins/watcher/server/plugin.ts +++ b/x-pack/plugins/watcher/server/plugin.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; - +import { SemVer } from 'semver'; import { CoreStart, CoreSetup, Logger, Plugin, PluginInitializerContext } from 'kibana/server'; import { PLUGIN, INDEX_NAMES } from '../common/constants'; @@ -27,17 +27,19 @@ export class WatcherServerPlugin implements Plugin { private readonly license: License; private readonly logger: Logger; - constructor(ctx: PluginInitializerContext) { + constructor(private ctx: PluginInitializerContext) { this.logger = ctx.logger.get(); this.license = new License(); } - setup({ http, getStartServices }: CoreSetup, { licensing, features }: SetupDependencies) { + setup({ http }: CoreSetup, { features }: SetupDependencies) { this.license.setup({ pluginName: PLUGIN.getI18nName(i18n), logger: this.logger, }); + const kibanaVersion = new SemVer(this.ctx.env.packageInfo.version); + const router = http.createRouter(); const routeDependencies: RouteDependencies = { router, @@ -45,6 +47,7 @@ export class WatcherServerPlugin implements Plugin { lib: { handleEsError, }, + kibanaVersion, }; features.registerElasticsearchFeature({ diff --git a/x-pack/plugins/watcher/server/routes/api/watch/register_visualize_route.ts b/x-pack/plugins/watcher/server/routes/api/watch/register_visualize_route.ts index 61836d0ebae47d..60442bf43bd689 100644 --- a/x-pack/plugins/watcher/server/routes/api/watch/register_visualize_route.ts +++ b/x-pack/plugins/watcher/server/routes/api/watch/register_visualize_route.ts @@ -37,6 +37,7 @@ export function registerVisualizeRoute({ router, license, lib: { handleEsError }, + kibanaVersion, }: RouteDependencies) { router.post( { @@ -48,7 +49,7 @@ export function registerVisualizeRoute({ license.guardApiRoute(async (ctx, request, response) => { const watch = Watch.fromDownstreamJson(request.body.watch); const options = VisualizeOptions.fromDownstreamJson(request.body.options); - const body = watch.getVisualizeQuery(options); + const body = watch.getVisualizeQuery(options, kibanaVersion); try { const hits = await fetchVisualizeData(ctx.core.elasticsearch.client, watch.index, body); diff --git a/x-pack/plugins/watcher/server/types.ts b/x-pack/plugins/watcher/server/types.ts index c9d43528d9ffac..87cd5e40c27920 100644 --- a/x-pack/plugins/watcher/server/types.ts +++ b/x-pack/plugins/watcher/server/types.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { SemVer } from 'semver'; import type { IRouter } from 'src/core/server'; import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server'; @@ -33,4 +34,5 @@ export interface RouteDependencies { lib: { handleEsError: typeof handleEsError; }; + kibanaVersion: SemVer; } diff --git a/x-pack/test/api_integration/apis/ml/trained_models/delete_model.ts b/x-pack/test/api_integration/apis/ml/trained_models/delete_model.ts index 3848330a95fb92..7124a9566c7105 100644 --- a/x-pack/test/api_integration/apis/ml/trained_models/delete_model.ts +++ b/x-pack/test/api_integration/apis/ml/trained_models/delete_model.ts @@ -17,7 +17,7 @@ export default ({ getService }: FtrProviderContext) => { describe('DELETE trained_models', () => { before(async () => { await ml.testResources.setKibanaTimeZoneToUTC(); - await ml.api.createdTestTrainedModels('regression', 2); + await ml.api.createTestTrainedModels('regression', 2); }); after(async () => { diff --git a/x-pack/test/api_integration/apis/ml/trained_models/get_model_pipelines.ts b/x-pack/test/api_integration/apis/ml/trained_models/get_model_pipelines.ts index cc347056f02a31..9600972e3e8bee 100644 --- a/x-pack/test/api_integration/apis/ml/trained_models/get_model_pipelines.ts +++ b/x-pack/test/api_integration/apis/ml/trained_models/get_model_pipelines.ts @@ -19,7 +19,7 @@ export default ({ getService }: FtrProviderContext) => { before(async () => { await ml.testResources.setKibanaTimeZoneToUTC(); - testModelIds = await ml.api.createdTestTrainedModels('regression', 2, true); + testModelIds = await ml.api.createTestTrainedModels('regression', 2, true); }); after(async () => { diff --git a/x-pack/test/api_integration/apis/ml/trained_models/get_model_stats.ts b/x-pack/test/api_integration/apis/ml/trained_models/get_model_stats.ts index 76f108836996f2..48040959f0e4bd 100644 --- a/x-pack/test/api_integration/apis/ml/trained_models/get_model_stats.ts +++ b/x-pack/test/api_integration/apis/ml/trained_models/get_model_stats.ts @@ -17,7 +17,7 @@ export default ({ getService }: FtrProviderContext) => { describe('GET trained_models/_stats', () => { before(async () => { await ml.testResources.setKibanaTimeZoneToUTC(); - await ml.api.createdTestTrainedModels('regression', 2); + await ml.api.createTestTrainedModels('regression', 2); }); after(async () => { diff --git a/x-pack/test/api_integration/apis/ml/trained_models/get_models.ts b/x-pack/test/api_integration/apis/ml/trained_models/get_models.ts index 604dff6a98a9af..ec33ef316828c5 100644 --- a/x-pack/test/api_integration/apis/ml/trained_models/get_models.ts +++ b/x-pack/test/api_integration/apis/ml/trained_models/get_models.ts @@ -19,7 +19,7 @@ export default ({ getService }: FtrProviderContext) => { before(async () => { await ml.testResources.setKibanaTimeZoneToUTC(); - testModelIds = await ml.api.createdTestTrainedModels('regression', 5, true); + testModelIds = await ml.api.createTestTrainedModels('regression', 5, true); await ml.api.createModelAlias('dfa_regression_model_n_0', 'dfa_regression_model_alias'); await ml.api.createIngestPipeline('dfa_regression_model_alias'); }); diff --git a/x-pack/test/api_integration/apis/uptime/rest/telemetry_collectors.ts b/x-pack/test/api_integration/apis/uptime/rest/telemetry_collectors.ts index 8e80208b3d805d..de65fe6deb9856 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/telemetry_collectors.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/telemetry_collectors.ts @@ -14,7 +14,8 @@ export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const es = getService('es'); - describe('telemetry collectors heartbeat', () => { + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/111240 + describe.skip('telemetry collectors heartbeat', () => { before('generating data', async () => { await getService('esArchiver').load('x-pack/test/functional/es_archives/uptime/blank'); diff --git a/x-pack/test/apm_api_integration/tests/alerts/chart_preview.ts b/x-pack/test/apm_api_integration/tests/alerts/chart_preview.ts index d3e5b082334870..621ed5dcfd8d7b 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/chart_preview.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/chart_preview.ts @@ -33,7 +33,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('transaction_error_rate (without data)', async () => { const options = getOptions(); const response = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/alerts/chart_preview/transaction_error_rate', + endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_error_rate', ...options, }); @@ -46,7 +46,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { options.params.query.transactionType = undefined; const response = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/alerts/chart_preview/transaction_error_count', + endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_error_count', ...options, }); @@ -58,7 +58,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const options = getOptions(); const response = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/alerts/chart_preview/transaction_duration', + endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_duration', ...options, }); @@ -71,7 +71,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('transaction_error_rate (with data)', async () => { const options = getOptions(); const response = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/alerts/chart_preview/transaction_error_rate', + endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_error_rate', ...options, }); @@ -88,7 +88,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { options.params.query.transactionType = undefined; const response = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/alerts/chart_preview/transaction_error_count', + endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_error_count', ...options, }); @@ -104,7 +104,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const options = getOptions(); const response = await apmApiClient.readUser({ ...options, - endpoint: 'GET /api/apm/alerts/chart_preview/transaction_duration', + endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_duration', }); expect(response.status).to.be(200); diff --git a/x-pack/test/apm_api_integration/tests/feature_controls.ts b/x-pack/test/apm_api_integration/tests/feature_controls.ts index 18fcf4fef5fec2..ef3ba5d61fb54b 100644 --- a/x-pack/test/apm_api_integration/tests/feature_controls.ts +++ b/x-pack/test/apm_api_integration/tests/feature_controls.ts @@ -44,87 +44,89 @@ export default function featureControlsTests({ getService }: FtrProviderContext) { // this doubles as a smoke test for the _inspect query parameter req: { - url: `/api/apm/services/foo/errors?start=${start}&end=${end}&_inspect=true&environment=ENVIRONMENT_ALL&kuery=`, + url: `/internal/apm/services/foo/errors?start=${start}&end=${end}&_inspect=true&environment=ENVIRONMENT_ALL&kuery=`, }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/errors/bar?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=`, + url: `/internal/apm/services/foo/errors/bar?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=`, }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/errors/distribution?start=${start}&end=${end}&groupId=bar&environment=ENVIRONMENT_ALL&kuery=`, + url: `/internal/apm/services/foo/errors/distribution?start=${start}&end=${end}&groupId=bar&environment=ENVIRONMENT_ALL&kuery=`, }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/errors/distribution?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=`, + url: `/internal/apm/services/foo/errors/distribution?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=`, }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/metrics/charts?start=${start}&end=${end}&agentName=cool-agent&environment=ENVIRONMENT_ALL&kuery=`, + url: `/internal/apm/services/foo/metrics/charts?start=${start}&end=${end}&agentName=cool-agent&environment=ENVIRONMENT_ALL&kuery=`, }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/services?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=`, + url: `/internal/apm/services?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=`, }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/agent?start=${start}&end=${end}`, + url: `/internal/apm/services/foo/agent?start=${start}&end=${end}`, }, expectForbidden: expect403, expectResponse: expect200, }, { - req: { url: `/api/apm/services/foo/transaction_types?start=${start}&end=${end}` }, + req: { url: `/internal/apm/services/foo/transaction_types?start=${start}&end=${end}` }, expectForbidden: expect403, expectResponse: expect200, }, { - req: { url: `/api/apm/traces?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` }, + req: { + url: `/internal/apm/traces?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=`, + }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/traces/foo?start=${start}&end=${end}`, + url: `/internal/apm/traces/foo?start=${start}&end=${end}`, }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/transactions/charts/latency?environment=testing&start=${start}&end=${end}&transactionType=bar&latencyAggregationType=avg&kuery=`, + url: `/internal/apm/services/foo/transactions/charts/latency?environment=testing&start=${start}&end=${end}&transactionType=bar&latencyAggregationType=avg&kuery=`, }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/transactions/charts/latency?environment=testing&start=${start}&end=${end}&transactionType=bar&latencyAggregationType=avg&transactionName=baz&kuery=`, + url: `/internal/apm/services/foo/transactions/charts/latency?environment=testing&start=${start}&end=${end}&transactionType=bar&latencyAggregationType=avg&transactionName=baz&kuery=`, }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/transactions/traces/samples?start=${start}&end=${end}&transactionType=bar&transactionName=baz&environment=ENVIRONMENT_ALL&kuery=`, + url: `/internal/apm/services/foo/transactions/traces/samples?start=${start}&end=${end}&transactionType=bar&transactionName=baz&environment=ENVIRONMENT_ALL&kuery=`, }, expectForbidden: expect403, expectResponse: expect200, @@ -147,21 +149,21 @@ export default function featureControlsTests({ getService }: FtrProviderContext) }, { req: { - url: `/api/apm/settings/custom_links/transaction`, + url: `/internal/apm/settings/custom_links/transaction`, }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/metadata/details?start=${start}&end=${end}`, + url: `/internal/apm/services/foo/metadata/details?start=${start}&end=${end}`, }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/metadata/icons?start=${start}&end=${end}`, + url: `/internal/apm/services/foo/metadata/icons?start=${start}&end=${end}`, }, expectForbidden: expect403, expectResponse: expect200, diff --git a/x-pack/test/apm_api_integration/tests/historical_data/has_data.ts b/x-pack/test/apm_api_integration/tests/historical_data/has_data.ts index ec3f0e5e7f3620..70048c3d392104 100644 --- a/x-pack/test/apm_api_integration/tests/historical_data/has_data.ts +++ b/x-pack/test/apm_api_integration/tests/historical_data/has_data.ts @@ -18,7 +18,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { { config: 'basic', archives: [] }, () => { it('handles the empty state', async () => { - const response = await supertest.get(`/api/apm/has_data`); + const response = await supertest.get(`/internal/apm/has_data`); expect(response.status).to.be(200); expect(response.body.hasData).to.be(false); @@ -31,7 +31,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { { config: 'basic', archives: [archiveName] }, () => { it('returns hasData: true', async () => { - const response = await supertest.get(`/api/apm/has_data`); + const response = await supertest.get(`/internal/apm/has_data`); expect(response.status).to.be(200); expect(response.body.hasData).to.be(true); diff --git a/x-pack/test/apm_api_integration/tests/index.ts b/x-pack/test/apm_api_integration/tests/index.ts index efe159b36e3d39..49f1ae91c62826 100644 --- a/x-pack/test/apm_api_integration/tests/index.ts +++ b/x-pack/test/apm_api_integration/tests/index.ts @@ -150,7 +150,7 @@ export default function apmApiIntegrationTests(providerContext: FtrProviderConte describe('traces/top_traces', function () { loadTestFile(require.resolve('./traces/top_traces')); }); - describe('/api/apm/traces/{traceId}', function () { + describe('/internal/apm/traces/{traceId}', function () { loadTestFile(require.resolve('./traces/trace_by_id')); }); diff --git a/x-pack/test/apm_api_integration/tests/inspect/inspect.ts b/x-pack/test/apm_api_integration/tests/inspect/inspect.ts index 95805f4ef4524a..75b5a02fff800b 100644 --- a/x-pack/test/apm_api_integration/tests/inspect/inspect.ts +++ b/x-pack/test/apm_api_integration/tests/inspect/inspect.ts @@ -21,7 +21,7 @@ export default function customLinksTests({ getService }: FtrProviderContext) { describe('when omitting `_inspect` query param', () => { it('returns response without `_inspect`', async () => { const { status, body } = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/environments', + endpoint: 'GET /internal/apm/environments', params: { query: { start: metadata.start, @@ -39,7 +39,7 @@ export default function customLinksTests({ getService }: FtrProviderContext) { describe('elasticsearch calls made with end-user auth are returned', () => { it('for environments', async () => { const { status, body } = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/environments', + endpoint: 'GET /internal/apm/environments', params: { query: { start: metadata.start, @@ -67,7 +67,7 @@ export default function customLinksTests({ getService }: FtrProviderContext) { describe('elasticsearch calls made with internal user are not return', () => { it('for custom links', async () => { const { status, body } = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/settings/custom_links', + endpoint: 'GET /internal/apm/settings/custom_links', params: { query: { 'service.name': 'opbeans-node', diff --git a/x-pack/test/apm_api_integration/tests/metadata/event_metadata.ts b/x-pack/test/apm_api_integration/tests/metadata/event_metadata.ts index d979f0bad1ec6c..fb98cc9a6abd02 100644 --- a/x-pack/test/apm_api_integration/tests/metadata/event_metadata.ts +++ b/x-pack/test/apm_api_integration/tests/metadata/event_metadata.ts @@ -40,7 +40,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const id = await getLastDocId(ProcessorEvent.transaction); const { body } = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/event_metadata/{processorEvent}/{id}', + endpoint: 'GET /internal/apm/event_metadata/{processorEvent}/{id}', params: { path: { processorEvent: ProcessorEvent.transaction, @@ -70,7 +70,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const id = await getLastDocId(ProcessorEvent.error); const { body } = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/event_metadata/{processorEvent}/{id}', + endpoint: 'GET /internal/apm/event_metadata/{processorEvent}/{id}', params: { path: { processorEvent: ProcessorEvent.error, @@ -100,7 +100,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const id = await getLastDocId(ProcessorEvent.span); const { body } = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/event_metadata/{processorEvent}/{id}', + endpoint: 'GET /internal/apm/event_metadata/{processorEvent}/{id}', params: { path: { processorEvent: ProcessorEvent.span, diff --git a/x-pack/test/apm_api_integration/tests/metrics_charts/metrics_charts.ts b/x-pack/test/apm_api_integration/tests/metrics_charts/metrics_charts.ts index a3e02984a16de5..8d3a18a44f02e1 100644 --- a/x-pack/test/apm_api_integration/tests/metrics_charts/metrics_charts.ts +++ b/x-pack/test/apm_api_integration/tests/metrics_charts/metrics_charts.ts @@ -33,7 +33,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { let chartsResponse: ChartResponse; before(async () => { chartsResponse = await supertest.get( - `/api/apm/services/opbeans-node/metrics/charts?start=${start}&end=${end}&agentName=${agentName}&kuery=&environment=ENVIRONMENT_ALL` + `/internal/apm/services/opbeans-node/metrics/charts?start=${start}&end=${end}&agentName=${agentName}&kuery=&environment=ENVIRONMENT_ALL` ); }); it('contains CPU usage and System memory usage chart data', async () => { @@ -121,7 +121,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { let chartsResponse: ChartResponse; before(async () => { chartsResponse = await supertest.get( - `/api/apm/services/opbeans-java/metrics/charts?start=${start}&end=${end}&agentName=${agentName}&environment=ENVIRONMENT_ALL&kuery=` + `/internal/apm/services/opbeans-java/metrics/charts?start=${start}&end=${end}&agentName=${agentName}&environment=ENVIRONMENT_ALL&kuery=` ); }); @@ -410,7 +410,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const end = encodeURIComponent('2020-09-08T15:05:00.000Z'); const chartsResponse: ChartResponse = await supertest.get( - `/api/apm/services/opbeans-java/metrics/charts?start=${start}&end=${end}&agentName=${agentName}&environment=ENVIRONMENT_ALL&kuery=` + `/internal/apm/services/opbeans-java/metrics/charts?start=${start}&end=${end}&agentName=${agentName}&environment=ENVIRONMENT_ALL&kuery=` ); const systemMemoryUsageChart = chartsResponse.body.charts.find( diff --git a/x-pack/test/apm_api_integration/tests/observability_overview/has_data.ts b/x-pack/test/apm_api_integration/tests/observability_overview/has_data.ts index 1b0f8fdcf87367..90a01c472e13e8 100644 --- a/x-pack/test/apm_api_integration/tests/observability_overview/has_data.ts +++ b/x-pack/test/apm_api_integration/tests/observability_overview/has_data.ts @@ -19,7 +19,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { it('returns false when there is no data', async () => { const response = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/observability_overview/has_data', + endpoint: 'GET /internal/apm/observability_overview/has_data', }); expect(response.status).to.be(200); expect(response.body.hasData).to.eql(false); @@ -33,7 +33,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { it('returns false when there is only onboarding data', async () => { const response = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/observability_overview/has_data', + endpoint: 'GET /internal/apm/observability_overview/has_data', }); expect(response.status).to.be(200); expect(response.body.hasData).to.eql(false); @@ -47,7 +47,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { it('returns true when there is at least one document on transaction, error or metrics indices', async () => { const response = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/observability_overview/has_data', + endpoint: 'GET /internal/apm/observability_overview/has_data', }); expect(response.status).to.be(200); expect(response.body.hasData).to.eql(true); diff --git a/x-pack/test/apm_api_integration/tests/observability_overview/observability_overview.ts b/x-pack/test/apm_api_integration/tests/observability_overview/observability_overview.ts index 76a157d72cc6f1..b463db81e6c99e 100644 --- a/x-pack/test/apm_api_integration/tests/observability_overview/observability_overview.ts +++ b/x-pack/test/apm_api_integration/tests/observability_overview/observability_overview.ts @@ -28,7 +28,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('when data is not loaded', () => { it('handles the empty state', async () => { const response = await supertest.get( - `/api/apm/observability_overview?start=${start}&end=${end}&bucketSize=${bucketSize}` + `/internal/apm/observability_overview?start=${start}&end=${end}&bucketSize=${bucketSize}` ); expect(response.status).to.be(200); @@ -45,7 +45,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { it('returns the service count and transaction coordinates', async () => { const response = await supertest.get( - `/api/apm/observability_overview?start=${start}&end=${end}&bucketSize=${bucketSize}` + `/internal/apm/observability_overview?start=${start}&end=${end}&bucketSize=${bucketSize}` ); expect(response.status).to.be(200); diff --git a/x-pack/test/apm_api_integration/tests/service_maps/__snapshots__/service_maps.snap b/x-pack/test/apm_api_integration/tests/service_maps/__snapshots__/service_maps.snap index c66609b8a8a913..9e32f311e8d115 100644 --- a/x-pack/test/apm_api_integration/tests/service_maps/__snapshots__/service_maps.snap +++ b/x-pack/test/apm_api_integration/tests/service_maps/__snapshots__/service_maps.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`APM API tests trial apm_8.0.0 Service Map with data /api/apm/service-map returns the correct data 3`] = ` +exports[`APM API tests trial apm_8.0.0 Service Map with data /internal/apm/service-map returns the correct data 3`] = ` Array [ Object { "data": Object { @@ -1376,7 +1376,7 @@ Array [ ] `; -exports[`APM API tests trial apm_8.0.0 Service Map with data /api/apm/service-map with ML data with the default apm user returns the correct anomaly stats 3`] = ` +exports[`APM API tests trial apm_8.0.0 Service Map with data /internal/apm/service-map with ML data with the default apm user returns the correct anomaly stats 3`] = ` Object { "elements": Array [ Object { diff --git a/x-pack/test/apm_api_integration/tests/service_maps/service_maps.ts b/x-pack/test/apm_api_integration/tests/service_maps/service_maps.ts index 816e4e26ef8692..37fe340d751943 100644 --- a/x-pack/test/apm_api_integration/tests/service_maps/service_maps.ts +++ b/x-pack/test/apm_api_integration/tests/service_maps/service_maps.ts @@ -28,7 +28,7 @@ export default function serviceMapsApiTests({ getService }: FtrProviderContext) registry.when('Service map with a basic license', { config: 'basic', archives: [] }, () => { it('is only be available to users with Platinum license (or higher)', async () => { const response = await supertest.get( - `/api/apm/service-map?start=${start}&end=${end}&environment=ENVIRONMENT_ALL` + `/internal/apm/service-map?start=${start}&end=${end}&environment=ENVIRONMENT_ALL` ); expect(response.status).to.be(403); @@ -40,10 +40,10 @@ export default function serviceMapsApiTests({ getService }: FtrProviderContext) }); registry.when('Service map without data', { config: 'trial', archives: [] }, () => { - describe('/api/apm/service-map', () => { + describe('/internal/apm/service-map', () => { it('returns an empty list', async () => { const response = await supertest.get( - `/api/apm/service-map?start=${start}&end=${end}&environment=ENVIRONMENT_ALL` + `/internal/apm/service-map?start=${start}&end=${end}&environment=ENVIRONMENT_ALL` ); expect(response.status).to.be(200); @@ -51,14 +51,14 @@ export default function serviceMapsApiTests({ getService }: FtrProviderContext) }); }); - describe('/api/apm/service-map/service/{serviceName}', () => { + describe('/internal/apm/service-map/service/{serviceName}', () => { it('returns an object with nulls', async () => { const q = querystring.stringify({ start: metadata.start, end: metadata.end, environment: 'ENVIRONMENT_ALL', }); - const response = await supertest.get(`/api/apm/service-map/service/opbeans-node?${q}`); + const response = await supertest.get(`/internal/apm/service-map/service/opbeans-node?${q}`); expect(response.status).to.be(200); @@ -76,14 +76,14 @@ export default function serviceMapsApiTests({ getService }: FtrProviderContext) }); }); - describe('/api/apm/service-map/backend/{backendName}', () => { + describe('/internal/apm/service-map/backend/{backendName}', () => { it('returns an object with nulls', async () => { const q = querystring.stringify({ start: metadata.start, end: metadata.end, environment: 'ENVIRONMENT_ALL', }); - const response = await supertest.get(`/api/apm/service-map/backend/postgres?${q}`); + const response = await supertest.get(`/internal/apm/service-map/backend/postgres?${q}`); expect(response.status).to.be(200); @@ -101,12 +101,12 @@ export default function serviceMapsApiTests({ getService }: FtrProviderContext) }); registry.when('Service Map with data', { config: 'trial', archives: ['apm_8.0.0'] }, () => { - describe('/api/apm/service-map', () => { + describe('/internal/apm/service-map', () => { let response: PromiseReturnType; before(async () => { response = await supertest.get( - `/api/apm/service-map?start=${start}&end=${end}&environment=ENVIRONMENT_ALL` + `/internal/apm/service-map?start=${start}&end=${end}&environment=ENVIRONMENT_ALL` ); }); @@ -159,7 +159,7 @@ export default function serviceMapsApiTests({ getService }: FtrProviderContext) describe('with the default apm user', () => { before(async () => { response = await supertest.get( - `/api/apm/service-map?start=${start}&end=${end}&environment=ENVIRONMENT_ALL` + `/internal/apm/service-map?start=${start}&end=${end}&environment=ENVIRONMENT_ALL` ); }); @@ -246,7 +246,7 @@ export default function serviceMapsApiTests({ getService }: FtrProviderContext) describe('with a user that does not have access to ML', () => { before(async () => { response = await supertestAsApmReadUserWithoutMlAccess.get( - `/api/apm/service-map?start=${start}&end=${end}&environment=ENVIRONMENT_ALL` + `/internal/apm/service-map?start=${start}&end=${end}&environment=ENVIRONMENT_ALL` ); }); @@ -267,7 +267,7 @@ export default function serviceMapsApiTests({ getService }: FtrProviderContext) it('returns service map elements', async () => { response = await supertest.get( url.format({ - pathname: '/api/apm/service-map', + pathname: '/internal/apm/service-map', query: { environment: 'ENVIRONMENT_ALL', start: metadata.start, @@ -284,14 +284,14 @@ export default function serviceMapsApiTests({ getService }: FtrProviderContext) }); }); - describe('/api/apm/service-map/service/{serviceName}', () => { + describe('/internal/apm/service-map/service/{serviceName}', () => { it('returns an object with data', async () => { const q = querystring.stringify({ start: metadata.start, end: metadata.end, environment: 'ENVIRONMENT_ALL', }); - const response = await supertest.get(`/api/apm/service-map/service/opbeans-node?${q}`); + const response = await supertest.get(`/internal/apm/service-map/service/opbeans-node?${q}`); expect(response.status).to.be(200); @@ -309,14 +309,14 @@ export default function serviceMapsApiTests({ getService }: FtrProviderContext) }); }); - describe('/api/apm/service-map/backend/{backendName}', () => { + describe('/internal/apm/service-map/backend/{backendName}', () => { it('returns an object with data', async () => { const q = querystring.stringify({ start: metadata.start, end: metadata.end, environment: 'ENVIRONMENT_ALL', }); - const response = await supertest.get(`/api/apm/service-map/backend/postgresql?${q}`); + const response = await supertest.get(`/internal/apm/service-map/backend/postgresql?${q}`); expect(response.status).to.be(200); diff --git a/x-pack/test/apm_api_integration/tests/service_overview/dependencies/index.ts b/x-pack/test/apm_api_integration/tests/service_overview/dependencies/index.ts index 4bd9785b314272..1e8acccbb192a5 100644 --- a/x-pack/test/apm_api_integration/tests/service_overview/dependencies/index.ts +++ b/x-pack/test/apm_api_integration/tests/service_overview/dependencies/index.ts @@ -37,7 +37,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { it('handles the empty state', async () => { const response = await apmApiClient.readUser({ - endpoint: `GET /api/apm/services/{serviceName}/dependencies`, + endpoint: `GET /internal/apm/services/{serviceName}/dependencies`, params: { path: { serviceName: 'opbeans-java' }, query: { @@ -61,7 +61,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { let response: { status: number; - body: APIReturnType<'GET /api/apm/services/{serviceName}/dependencies'>; + body: APIReturnType<'GET /internal/apm/services/{serviceName}/dependencies'>; }; const indices = { @@ -212,7 +212,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); response = await apmApiClient.readUser({ - endpoint: `GET /api/apm/services/{serviceName}/dependencies`, + endpoint: `GET /internal/apm/services/{serviceName}/dependencies`, params: { path: { serviceName: 'opbeans-java' }, query: { @@ -309,12 +309,12 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { let response: { status: number; - body: APIReturnType<'GET /api/apm/services/{serviceName}/dependencies'>; + body: APIReturnType<'GET /internal/apm/services/{serviceName}/dependencies'>; }; before(async () => { response = await apmApiClient.readUser({ - endpoint: `GET /api/apm/services/{serviceName}/dependencies`, + endpoint: `GET /internal/apm/services/{serviceName}/dependencies`, params: { path: { serviceName: 'opbeans-python' }, query: { diff --git a/x-pack/test/apm_api_integration/tests/service_overview/get_service_node_ids.ts b/x-pack/test/apm_api_integration/tests/service_overview/get_service_node_ids.ts index 1472c1f8c1a09a..019c41f9292bad 100644 --- a/x-pack/test/apm_api_integration/tests/service_overview/get_service_node_ids.ts +++ b/x-pack/test/apm_api_integration/tests/service_overview/get_service_node_ids.ts @@ -22,7 +22,7 @@ export async function getServiceNodeIds({ count?: number; }) { const { body } = await apmApiSupertest({ - endpoint: `GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics`, + endpoint: `GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics`, params: { path: { serviceName }, query: { diff --git a/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts b/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts index d2b6136fafebfe..f3de8823199a88 100644 --- a/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts +++ b/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts @@ -14,7 +14,7 @@ import { getServiceNodeIds } from './get_service_node_ids'; import { createApmApiClient } from '../../common/apm_api_supertest'; type ServiceOverviewInstanceDetails = - APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}'>; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('legacySupertestAsApmReadUser'); @@ -31,7 +31,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('handles empty state', async () => { const response = await supertest.get( url.format({ - pathname: '/api/apm/services/opbeans-java/service_overview_instances/details/foo', + pathname: + '/internal/apm/services/opbeans-java/service_overview_instances/details/foo', query: { start, end, @@ -62,7 +63,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { serviceNodeIds = await getServiceNodeIds({ apmApiSupertest, start, end }); response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/service_overview_instances/details/${serviceNodeIds[0]}`, + pathname: `/internal/apm/services/opbeans-java/service_overview_instances/details/${serviceNodeIds[0]}`, query: { start, end, @@ -89,7 +90,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('handles empty state when instance id not found', async () => { const response = await supertest.get( url.format({ - pathname: '/api/apm/services/opbeans-java/service_overview_instances/details/foo', + pathname: '/internal/apm/services/opbeans-java/service_overview_instances/details/foo', query: { start, end, diff --git a/x-pack/test/apm_api_integration/tests/service_overview/instances_detailed_statistics.ts b/x-pack/test/apm_api_integration/tests/service_overview/instances_detailed_statistics.ts index 1ad272bafaa808..9d9fb6a221cf68 100644 --- a/x-pack/test/apm_api_integration/tests/service_overview/instances_detailed_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/service_overview/instances_detailed_statistics.ts @@ -26,7 +26,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { interface Response { status: number; - body: APIReturnType<'GET /api/apm/services/{serviceName}/service_overview_instances/detailed_statistics'>; + body: APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics'>; } registry.when( @@ -37,7 +37,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('handles the empty state', async () => { const response: Response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/service_overview_instances/detailed_statistics`, + pathname: `/internal/apm/services/opbeans-java/service_overview_instances/detailed_statistics`, query: { latencyAggregationType: 'avg', start, @@ -75,7 +75,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { beforeEach(async () => { response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/service_overview_instances/detailed_statistics`, + pathname: `/internal/apm/services/opbeans-java/service_overview_instances/detailed_statistics`, query: { latencyAggregationType: 'avg', start, @@ -129,7 +129,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { beforeEach(async () => { response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/service_overview_instances/detailed_statistics`, + pathname: `/internal/apm/services/opbeans-java/service_overview_instances/detailed_statistics`, query: { latencyAggregationType: 'avg', numBuckets: 20, diff --git a/x-pack/test/apm_api_integration/tests/service_overview/instances_main_statistics.ts b/x-pack/test/apm_api_integration/tests/service_overview/instances_main_statistics.ts index 355778757af3c6..2d165f4ceb902a 100644 --- a/x-pack/test/apm_api_integration/tests/service_overview/instances_main_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/service_overview/instances_main_statistics.ts @@ -29,7 +29,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('when data is not loaded', () => { it('handles the empty state', async () => { const response = await apmApiClient.readUser({ - endpoint: `GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics`, + endpoint: `GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics`, params: { path: { serviceName: 'opbeans-java' }, query: { @@ -58,12 +58,12 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { describe('fetching java data', () => { let response: { - body: APIReturnType<`GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics`>; + body: APIReturnType<`GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics`>; }; beforeEach(async () => { response = await apmApiClient.readUser({ - endpoint: `GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics`, + endpoint: `GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics`, params: { path: { serviceName: 'opbeans-java' }, query: { @@ -129,12 +129,12 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('fetching non-java data', () => { let response: { - body: APIReturnType<`GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics`>; + body: APIReturnType<`GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics`>; }; beforeEach(async () => { response = await apmApiClient.readUser({ - endpoint: `GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics`, + endpoint: `GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics`, params: { path: { serviceName: 'opbeans-ruby' }, query: { @@ -197,12 +197,12 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { describe('fetching java data', () => { let response: { - body: APIReturnType<`GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics`>; + body: APIReturnType<`GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics`>; }; beforeEach(async () => { response = await apmApiClient.readUser({ - endpoint: `GET /api/apm/services/{serviceName}/service_overview_instances/main_statistics`, + endpoint: `GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics`, params: { path: { serviceName: 'opbeans-java' }, query: { diff --git a/x-pack/test/apm_api_integration/tests/services/agent.ts b/x-pack/test/apm_api_integration/tests/services/agent.ts index 3e44dbe685cd8d..fcd21f5a1a072b 100644 --- a/x-pack/test/apm_api_integration/tests/services/agent.ts +++ b/x-pack/test/apm_api_integration/tests/services/agent.ts @@ -21,7 +21,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when('Agent name when data is not loaded', { config: 'basic', archives: [] }, () => { it('handles the empty state', async () => { const response = await supertest.get( - `/api/apm/services/opbeans-node/agent?start=${start}&end=${end}` + `/internal/apm/services/opbeans-node/agent?start=${start}&end=${end}` ); expect(response.status).to.be(200); @@ -35,7 +35,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { it('returns the agent name', async () => { const response = await supertest.get( - `/api/apm/services/opbeans-node/agent?start=${start}&end=${end}` + `/internal/apm/services/opbeans-node/agent?start=${start}&end=${end}` ); expect(response.status).to.be(200); diff --git a/x-pack/test/apm_api_integration/tests/services/error_groups_detailed_statistics.ts b/x-pack/test/apm_api_integration/tests/services/error_groups_detailed_statistics.ts index 7c7a5b5e9c51fb..3587a3e96c0d16 100644 --- a/x-pack/test/apm_api_integration/tests/services/error_groups_detailed_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/services/error_groups_detailed_statistics.ts @@ -16,7 +16,7 @@ import { createApmApiClient } from '../../common/apm_api_supertest'; import { getErrorGroupIds } from './get_error_group_ids'; type ErrorGroupsDetailedStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/error_groups/detailed_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/error_groups/detailed_statistics'>; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('legacySupertestAsApmReadUser'); @@ -35,7 +35,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/error_groups/detailed_statistics`, + pathname: `/internal/apm/services/opbeans-java/error_groups/detailed_statistics`, query: { start, end, @@ -63,7 +63,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/error_groups/detailed_statistics`, + pathname: `/internal/apm/services/opbeans-java/error_groups/detailed_statistics`, query: { start, end, @@ -98,7 +98,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns an empty state when requested groupIds are not available in the given time range', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/error_groups/detailed_statistics`, + pathname: `/internal/apm/services/opbeans-java/error_groups/detailed_statistics`, query: { start, end, @@ -133,7 +133,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/error_groups/detailed_statistics`, + pathname: `/internal/apm/services/opbeans-java/error_groups/detailed_statistics`, query: { numBuckets: 20, transactionType: 'request', @@ -179,7 +179,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns an empty state when requested groupIds are not available in the given time range', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/error_groups/detailed_statistics`, + pathname: `/internal/apm/services/opbeans-java/error_groups/detailed_statistics`, query: { numBuckets: 20, transactionType: 'request', diff --git a/x-pack/test/apm_api_integration/tests/services/error_groups_main_statistics.ts b/x-pack/test/apm_api_integration/tests/services/error_groups_main_statistics.ts index 98c906fe61192e..b6fb0696f3f74d 100644 --- a/x-pack/test/apm_api_integration/tests/services/error_groups_main_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/services/error_groups_main_statistics.ts @@ -13,7 +13,7 @@ import { registry } from '../../common/registry'; import { APIReturnType } from '../../../../plugins/apm/public/services/rest/createCallApmApi'; type ErrorGroupsMainStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/error_groups/main_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/error_groups/main_statistics'>; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('legacySupertestAsApmReadUser'); @@ -29,7 +29,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('handles empty state', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/error_groups/main_statistics`, + pathname: `/internal/apm/services/opbeans-java/error_groups/main_statistics`, query: { start, end, @@ -56,7 +56,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns the correct data', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/error_groups/main_statistics`, + pathname: `/internal/apm/services/opbeans-java/error_groups/main_statistics`, query: { start, end, diff --git a/x-pack/test/apm_api_integration/tests/services/get_error_group_ids.ts b/x-pack/test/apm_api_integration/tests/services/get_error_group_ids.ts index b2253750ae7f97..9fa7232240db19 100644 --- a/x-pack/test/apm_api_integration/tests/services/get_error_group_ids.ts +++ b/x-pack/test/apm_api_integration/tests/services/get_error_group_ids.ts @@ -21,7 +21,7 @@ export async function getErrorGroupIds({ count?: number; }) { const { body } = await apmApiSupertest({ - endpoint: `GET /api/apm/services/{serviceName}/error_groups/main_statistics`, + endpoint: `GET /internal/apm/services/{serviceName}/error_groups/main_statistics`, params: { path: { serviceName }, query: { diff --git a/x-pack/test/apm_api_integration/tests/services/service_details.ts b/x-pack/test/apm_api_integration/tests/services/service_details.ts index 263aaa504946bf..28a3ee3ef82fde 100644 --- a/x-pack/test/apm_api_integration/tests/services/service_details.ts +++ b/x-pack/test/apm_api_integration/tests/services/service_details.ts @@ -24,7 +24,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('handles the empty state', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/metadata/details`, + pathname: `/internal/apm/services/opbeans-java/metadata/details`, query: { start, end }, }) ); @@ -42,7 +42,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns java service details', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/metadata/details`, + pathname: `/internal/apm/services/opbeans-java/metadata/details`, query: { start, end }, }) ); @@ -88,7 +88,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns python service details', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-python/metadata/details`, + pathname: `/internal/apm/services/opbeans-python/metadata/details`, query: { start, end }, }) ); diff --git a/x-pack/test/apm_api_integration/tests/services/service_icons.ts b/x-pack/test/apm_api_integration/tests/services/service_icons.ts index 619603efc4128f..e948c6981d6c6f 100644 --- a/x-pack/test/apm_api_integration/tests/services/service_icons.ts +++ b/x-pack/test/apm_api_integration/tests/services/service_icons.ts @@ -21,7 +21,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('handles the empty state', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/metadata/icons`, + pathname: `/internal/apm/services/opbeans-java/metadata/icons`, query: { start, end }, }) ); @@ -38,7 +38,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns java service icons', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/metadata/icons`, + pathname: `/internal/apm/services/opbeans-java/metadata/icons`, query: { start, end }, }) ); @@ -57,7 +57,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns python service icons', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-python/metadata/icons`, + pathname: `/internal/apm/services/opbeans-python/metadata/icons`, query: { start, end }, }) ); diff --git a/x-pack/test/apm_api_integration/tests/services/services_detailed_statistics.ts b/x-pack/test/apm_api_integration/tests/services/services_detailed_statistics.ts index c5c1032a794f95..d605c5f3138256 100644 --- a/x-pack/test/apm_api_integration/tests/services/services_detailed_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/services/services_detailed_statistics.ts @@ -13,7 +13,8 @@ import { FtrProviderContext } from '../../common/ftr_provider_context'; import { APIReturnType } from '../../../../plugins/apm/public/services/rest/createCallApmApi'; import { isFiniteNumber } from '../../../../plugins/apm/common/utils/is_finite_number'; -type ServicesDetailedStatisticsReturn = APIReturnType<'GET /api/apm/services/detailed_statistics'>; +type ServicesDetailedStatisticsReturn = + APIReturnType<'GET /internal/apm/services/detailed_statistics'>; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('legacySupertestAsApmReadUser'); @@ -30,7 +31,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('handles the empty state', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/detailed_statistics`, + pathname: `/internal/apm/services/detailed_statistics`, query: { start, end, @@ -56,7 +57,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { before(async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/detailed_statistics`, + pathname: `/internal/apm/services/detailed_statistics`, query: { start, end, @@ -107,7 +108,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns empty when empty service names is passed', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/detailed_statistics`, + pathname: `/internal/apm/services/detailed_statistics`, query: { start, end, @@ -124,7 +125,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('filters by environment', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/detailed_statistics`, + pathname: `/internal/apm/services/detailed_statistics`, query: { start, end, @@ -141,7 +142,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('filters by kuery', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/detailed_statistics`, + pathname: `/internal/apm/services/detailed_statistics`, query: { start, end, @@ -165,7 +166,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { before(async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/detailed_statistics`, + pathname: `/internal/apm/services/detailed_statistics`, query: { start: moment(end).subtract(15, 'minutes').toISOString(), end, diff --git a/x-pack/test/apm_api_integration/tests/services/throughput.ts b/x-pack/test/apm_api_integration/tests/services/throughput.ts index 53c7efe28a6b59..d960cccc2877ee 100644 --- a/x-pack/test/apm_api_integration/tests/services/throughput.ts +++ b/x-pack/test/apm_api_integration/tests/services/throughput.ts @@ -17,7 +17,7 @@ import archives_metadata from '../../common/fixtures/es_archiver/archives_metada import { FtrProviderContext } from '../../common/ftr_provider_context'; import { registry } from '../../common/registry'; -type ThroughputReturn = APIReturnType<'GET /api/apm/services/{serviceName}/throughput'>; +type ThroughputReturn = APIReturnType<'GET /internal/apm/services/{serviceName}/throughput'>; export default function ApiTest({ getService }: FtrProviderContext) { const apmApiClient = getService('apmApiClient'); @@ -92,7 +92,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { kuery?: string; }) { const response = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/services/{serviceName}/throughput', + endpoint: 'GET /internal/apm/services/{serviceName}/throughput', params: { path: { serviceName: 'synth-go', @@ -166,7 +166,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when('Throughput when data is not loaded', { config: 'basic', archives: [] }, () => { it('handles the empty state', async () => { const response = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/services/{serviceName}/throughput', + endpoint: 'GET /internal/apm/services/{serviceName}/throughput', params: { path: { serviceName: 'opbeans-java', @@ -195,7 +195,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('when querying without kql filter', () => { before(async () => { const response = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/services/{serviceName}/throughput', + endpoint: 'GET /internal/apm/services/{serviceName}/throughput', params: { path: { serviceName: 'opbeans-java', @@ -249,7 +249,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('with kql filter to force transaction-based UI', () => { before(async () => { const response = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/services/{serviceName}/throughput', + endpoint: 'GET /internal/apm/services/{serviceName}/throughput', params: { path: { serviceName: 'opbeans-java', @@ -285,7 +285,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { before(async () => { const response = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/services/{serviceName}/throughput', + endpoint: 'GET /internal/apm/services/{serviceName}/throughput', params: { path: { serviceName: 'opbeans-java', diff --git a/x-pack/test/apm_api_integration/tests/services/top_services.ts b/x-pack/test/apm_api_integration/tests/services/top_services.ts index 8e79d6cda58e12..18700fb0412529 100644 --- a/x-pack/test/apm_api_integration/tests/services/top_services.ts +++ b/x-pack/test/apm_api_integration/tests/services/top_services.ts @@ -33,7 +33,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { it('handles the empty state', async () => { const response = await supertest.get( - `/api/apm/services?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` + `/internal/apm/services?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` ); expect(response.status).to.be(200); @@ -49,14 +49,14 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { let response: { status: number; - body: APIReturnType<'GET /api/apm/services'>; + body: APIReturnType<'GET /internal/apm/services'>; }; let sortedItems: typeof response.body.items; before(async () => { response = await supertest.get( - `/api/apm/services?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` + `/internal/apm/services?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` ); sortedItems = sortBy(response.body.items, 'serviceName'); }); @@ -192,15 +192,15 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('includes services that only report metric data', async () => { interface Response { status: number; - body: APIReturnType<'GET /api/apm/services'>; + body: APIReturnType<'GET /internal/apm/services'>; } const [unfilteredResponse, filteredResponse] = await Promise.all([ supertest.get( - `/api/apm/services?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` + `/internal/apm/services?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` ) as Promise, supertest.get( - `/api/apm/services?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=${encodeURIComponent( + `/internal/apm/services?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=${encodeURIComponent( 'not (processor.event:transaction)' )}` ) as Promise, @@ -231,12 +231,12 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('and fetching a list of services', () => { let response: { status: number; - body: APIReturnType<'GET /api/apm/services'>; + body: APIReturnType<'GET /internal/apm/services'>; }; before(async () => { response = await supertest.get( - `/api/apm/services?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` + `/internal/apm/services?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` ); }); @@ -282,7 +282,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { let response: PromiseReturnType; before(async () => { response = await supertestAsApmReadUserWithoutMlAccess.get( - `/api/apm/services?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` + `/internal/apm/services?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` ); }); @@ -307,7 +307,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { let response: PromiseReturnType; before(async () => { response = await supertest.get( - `/api/apm/services?environment=ENVIRONMENT_ALL&start=${start}&end=${end}&kuery=${encodeURIComponent( + `/internal/apm/services?environment=ENVIRONMENT_ALL&start=${start}&end=${end}&kuery=${encodeURIComponent( 'service.name:opbeans-java' )}` ); diff --git a/x-pack/test/apm_api_integration/tests/services/transaction_types.ts b/x-pack/test/apm_api_integration/tests/services/transaction_types.ts index 6f574b5c8e9978..4b752971e82f8a 100644 --- a/x-pack/test/apm_api_integration/tests/services/transaction_types.ts +++ b/x-pack/test/apm_api_integration/tests/services/transaction_types.ts @@ -26,7 +26,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { it('handles empty state', async () => { const response = await supertest.get( - `/api/apm/services/opbeans-node/transaction_types?start=${start}&end=${end}` + `/internal/apm/services/opbeans-node/transaction_types?start=${start}&end=${end}` ); expect(response.status).to.be(200); @@ -42,7 +42,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { it('handles empty state', async () => { const response = await supertest.get( - `/api/apm/services/opbeans-node/transaction_types?start=${start}&end=${end}` + `/internal/apm/services/opbeans-node/transaction_types?start=${start}&end=${end}` ); expect(response.status).to.be(200); diff --git a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/basic.ts b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/basic.ts index 40708adb754a84..7e05bd3faabfae 100644 --- a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/basic.ts +++ b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/basic.ts @@ -17,12 +17,12 @@ export default function apiTest({ getService }: FtrProviderContext) { type SupertestAsUser = typeof noAccessUser | typeof readUser | typeof writeUser; function getJobs(user: SupertestAsUser) { - return user.get(`/api/apm/settings/anomaly-detection/jobs`).set('kbn-xsrf', 'foo'); + return user.get(`/internal/apm/settings/anomaly-detection/jobs`).set('kbn-xsrf', 'foo'); } function createJobs(user: SupertestAsUser, environments: string[]) { return user - .post(`/api/apm/settings/anomaly-detection/jobs`) + .post(`/internal/apm/settings/anomaly-detection/jobs`) .send({ environments }) .set('kbn-xsrf', 'foo'); } diff --git a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/no_access_user.ts b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/no_access_user.ts index 135038755dc6ee..0b73b67c8e4c23 100644 --- a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/no_access_user.ts +++ b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/no_access_user.ts @@ -13,12 +13,12 @@ export default function apiTest({ getService }: FtrProviderContext) { const noAccessUser = getService('legacySupertestAsNoAccessUser'); function getJobs() { - return noAccessUser.get(`/api/apm/settings/anomaly-detection/jobs`).set('kbn-xsrf', 'foo'); + return noAccessUser.get(`/internal/apm/settings/anomaly-detection/jobs`).set('kbn-xsrf', 'foo'); } function createJobs(environments: string[]) { return noAccessUser - .post(`/api/apm/settings/anomaly-detection/jobs`) + .post(`/internal/apm/settings/anomaly-detection/jobs`) .send({ environments }) .set('kbn-xsrf', 'foo'); } diff --git a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/read_user.ts b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/read_user.ts index 3beebb434b3179..982a47001f826f 100644 --- a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/read_user.ts +++ b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/read_user.ts @@ -13,12 +13,12 @@ export default function apiTest({ getService }: FtrProviderContext) { const apmReadUser = getService('legacySupertestAsApmReadUser'); function getJobs() { - return apmReadUser.get(`/api/apm/settings/anomaly-detection/jobs`).set('kbn-xsrf', 'foo'); + return apmReadUser.get(`/internal/apm/settings/anomaly-detection/jobs`).set('kbn-xsrf', 'foo'); } function createJobs(environments: string[]) { return apmReadUser - .post(`/api/apm/settings/anomaly-detection/jobs`) + .post(`/internal/apm/settings/anomaly-detection/jobs`) .send({ environments }) .set('kbn-xsrf', 'foo'); } diff --git a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/write_user.ts b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/write_user.ts index 7c13533a142913..3d671c8fb825e4 100644 --- a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/write_user.ts +++ b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/write_user.ts @@ -15,12 +15,14 @@ export default function apiTest({ getService }: FtrProviderContext) { const legacyWriteUserClient = getService('legacySupertestAsApmWriteUser'); function getJobs() { - return apmApiClient.writeUser({ endpoint: `GET /api/apm/settings/anomaly-detection/jobs` }); + return apmApiClient.writeUser({ + endpoint: `GET /internal/apm/settings/anomaly-detection/jobs`, + }); } function createJobs(environments: string[]) { return apmApiClient.writeUser({ - endpoint: `POST /api/apm/settings/anomaly-detection/jobs`, + endpoint: `POST /internal/apm/settings/anomaly-detection/jobs`, params: { body: { environments }, }, diff --git a/x-pack/test/apm_api_integration/tests/settings/custom_link.ts b/x-pack/test/apm_api_integration/tests/settings/custom_link.ts index 03b2ad4aa32129..86f60be3fdc4cb 100644 --- a/x-pack/test/apm_api_integration/tests/settings/custom_link.ts +++ b/x-pack/test/apm_api_integration/tests/settings/custom_link.ts @@ -126,7 +126,7 @@ export default function customLinksTests({ getService }: FtrProviderContext) { it('fetches a transaction sample', async () => { const response = await apmApiClient.readUser({ - endpoint: 'GET /api/apm/settings/custom_links/transaction', + endpoint: 'GET /internal/apm/settings/custom_links/transaction', params: { query: { 'service.name': 'opbeans-java', @@ -141,7 +141,7 @@ export default function customLinksTests({ getService }: FtrProviderContext) { function searchCustomLinks(filters?: any) { return apmApiClient.readUser({ - endpoint: 'GET /api/apm/settings/custom_links', + endpoint: 'GET /internal/apm/settings/custom_links', params: { query: filters, }, @@ -152,7 +152,7 @@ export default function customLinksTests({ getService }: FtrProviderContext) { log.debug('creating configuration', customLink); return apmApiClient.writeUser({ - endpoint: 'POST /api/apm/settings/custom_links', + endpoint: 'POST /internal/apm/settings/custom_links', params: { body: customLink, }, @@ -163,7 +163,7 @@ export default function customLinksTests({ getService }: FtrProviderContext) { log.debug('updating configuration', id, customLink); return apmApiClient.writeUser({ - endpoint: 'PUT /api/apm/settings/custom_links/{id}', + endpoint: 'PUT /internal/apm/settings/custom_links/{id}', params: { path: { id }, body: customLink, @@ -175,7 +175,7 @@ export default function customLinksTests({ getService }: FtrProviderContext) { log.debug('deleting configuration', id); return apmApiClient.writeUser({ - endpoint: 'DELETE /api/apm/settings/custom_links/{id}', + endpoint: 'DELETE /internal/apm/settings/custom_links/{id}', params: { path: { id } }, }); } diff --git a/x-pack/test/apm_api_integration/tests/traces/top_traces.ts b/x-pack/test/apm_api_integration/tests/traces/top_traces.ts index 705c3d9ff4a15d..4968732f822033 100644 --- a/x-pack/test/apm_api_integration/tests/traces/top_traces.ts +++ b/x-pack/test/apm_api_integration/tests/traces/top_traces.ts @@ -24,7 +24,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when('Top traces when data is not loaded', { config: 'basic', archives: [] }, () => { it('handles empty state', async () => { const response = await supertest.get( - `/api/apm/traces?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` + `/internal/apm/traces?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` ); expect(response.status).to.be(200); @@ -39,7 +39,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { let response: any; before(async () => { response = await supertest.get( - `/api/apm/traces?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` + `/internal/apm/traces?start=${start}&end=${end}&environment=ENVIRONMENT_ALL&kuery=` ); }); diff --git a/x-pack/test/apm_api_integration/tests/traces/trace_by_id.tsx b/x-pack/test/apm_api_integration/tests/traces/trace_by_id.tsx index 5b4ab5f45da497..d99a2b95a792e2 100644 --- a/x-pack/test/apm_api_integration/tests/traces/trace_by_id.tsx +++ b/x-pack/test/apm_api_integration/tests/traces/trace_by_id.tsx @@ -22,7 +22,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when('Trace does not exist', { config: 'basic', archives: [] }, () => { it('handles empty state', async () => { const response = await apmApiSupertest({ - endpoint: `GET /api/apm/traces/{traceId}`, + endpoint: `GET /internal/apm/traces/{traceId}`, params: { path: { traceId: 'foo' }, query: { start, end }, @@ -35,10 +35,10 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); registry.when('Trace exists', { config: 'basic', archives: [archiveName] }, () => { - let response: SupertestReturnType<`GET /api/apm/traces/{traceId}`>; + let response: SupertestReturnType<`GET /internal/apm/traces/{traceId}`>; before(async () => { response = await apmApiSupertest({ - endpoint: `GET /api/apm/traces/{traceId}`, + endpoint: `GET /internal/apm/traces/{traceId}`, params: { path: { traceId: '64d0014f7530df24e549dd17cc0a8895' }, query: { start, end }, diff --git a/x-pack/test/apm_api_integration/tests/transactions/breakdown.ts b/x-pack/test/apm_api_integration/tests/transactions/breakdown.ts index de23b8fea53630..bc2e2f534a0bba 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/breakdown.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/breakdown.ts @@ -24,7 +24,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when('Breakdown when data is not loaded', { config: 'basic', archives: [] }, () => { it('handles the empty state', async () => { const response = await supertest.get( - `/api/apm/services/opbeans-node/transaction/charts/breakdown?start=${start}&end=${end}&transactionType=${transactionType}&environment=ENVIRONMENT_ALL&kuery=` + `/internal/apm/services/opbeans-node/transaction/charts/breakdown?start=${start}&end=${end}&transactionType=${transactionType}&environment=ENVIRONMENT_ALL&kuery=` ); expect(response.status).to.be(200); expect(response.body).to.eql({ timeseries: [] }); @@ -37,7 +37,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { it('returns the transaction breakdown for a service', async () => { const response = await supertest.get( - `/api/apm/services/opbeans-node/transaction/charts/breakdown?start=${start}&end=${end}&transactionType=${transactionType}&environment=ENVIRONMENT_ALL&kuery=` + `/internal/apm/services/opbeans-node/transaction/charts/breakdown?start=${start}&end=${end}&transactionType=${transactionType}&environment=ENVIRONMENT_ALL&kuery=` ); expect(response.status).to.be(200); @@ -45,7 +45,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); it('returns the transaction breakdown for a transaction group', async () => { const response = await supertest.get( - `/api/apm/services/opbeans-node/transaction/charts/breakdown?start=${start}&end=${end}&transactionType=${transactionType}&transactionName=${transactionName}&environment=ENVIRONMENT_ALL&kuery=` + `/internal/apm/services/opbeans-node/transaction/charts/breakdown?start=${start}&end=${end}&transactionType=${transactionType}&transactionName=${transactionName}&environment=ENVIRONMENT_ALL&kuery=` ); expect(response.status).to.be(200); @@ -104,7 +104,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); it('returns the transaction breakdown sorted by name', async () => { const response = await supertest.get( - `/api/apm/services/opbeans-node/transaction/charts/breakdown?start=${start}&end=${end}&transactionType=${transactionType}&environment=ENVIRONMENT_ALL&kuery=` + `/internal/apm/services/opbeans-node/transaction/charts/breakdown?start=${start}&end=${end}&transactionType=${transactionType}&environment=ENVIRONMENT_ALL&kuery=` ); expect(response.status).to.be(200); diff --git a/x-pack/test/apm_api_integration/tests/transactions/error_rate.ts b/x-pack/test/apm_api_integration/tests/transactions/error_rate.ts index d06eebd2cb9826..2ddaa4677394c6 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/error_rate.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/error_rate.ts @@ -15,7 +15,7 @@ import { FtrProviderContext } from '../../common/ftr_provider_context'; import { registry } from '../../common/registry'; type ErrorRate = - APIReturnType<'GET /api/apm/services/{serviceName}/transactions/charts/error_rate'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/charts/error_rate'>; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('legacySupertestAsApmReadUser'); @@ -30,7 +30,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('handles the empty state', async () => { const response = await supertest.get( format({ - pathname: '/api/apm/services/opbeans-java/transactions/charts/error_rate', + pathname: '/internal/apm/services/opbeans-java/transactions/charts/error_rate', query: { start, end, transactionType, environment: 'ENVIRONMENT_ALL', kuery: '' }, }) ); @@ -46,7 +46,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('handles the empty state with comparison data', async () => { const response = await supertest.get( format({ - pathname: '/api/apm/services/opbeans-java/transactions/charts/error_rate', + pathname: '/internal/apm/services/opbeans-java/transactions/charts/error_rate', query: { transactionType, start: moment(end).subtract(15, 'minutes').toISOString(), @@ -78,7 +78,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { before(async () => { const response = await supertest.get( format({ - pathname: '/api/apm/services/opbeans-java/transactions/charts/error_rate', + pathname: '/internal/apm/services/opbeans-java/transactions/charts/error_rate', query: { start, end, transactionType, environment: 'ENVIRONMENT_ALL', kuery: '' }, }) ); @@ -138,7 +138,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { before(async () => { const response = await supertest.get( format({ - pathname: '/api/apm/services/opbeans-java/transactions/charts/error_rate', + pathname: '/internal/apm/services/opbeans-java/transactions/charts/error_rate', query: { transactionType, start: moment(end).subtract(15, 'minutes').toISOString(), diff --git a/x-pack/test/apm_api_integration/tests/transactions/latency.ts b/x-pack/test/apm_api_integration/tests/transactions/latency.ts index df6daa89738011..beaff7647868a5 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/latency.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/latency.ts @@ -15,7 +15,7 @@ import archives_metadata from '../../common/fixtures/es_archiver/archives_metada import { registry } from '../../common/registry'; type LatencyChartReturnType = - APIReturnType<'GET /api/apm/services/{serviceName}/transactions/charts/latency'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/charts/latency'>; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('legacySupertestAsApmReadUser'); @@ -31,7 +31,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns 400 when latencyAggregationType is not informed', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-node/transactions/charts/latency`, + pathname: `/internal/apm/services/opbeans-node/transactions/charts/latency`, query: { start, end, @@ -47,7 +47,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns 400 when transactionType is not informed', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-node/transactions/charts/latency`, + pathname: `/internal/apm/services/opbeans-node/transactions/charts/latency`, query: { start, end, @@ -63,7 +63,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('handles the empty state', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-node/transactions/charts/latency`, + pathname: `/internal/apm/services/opbeans-node/transactions/charts/latency`, query: { start, end, @@ -96,7 +96,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { before(async () => { response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-node/transactions/charts/latency`, + pathname: `/internal/apm/services/opbeans-node/transactions/charts/latency`, query: { start, end, @@ -121,7 +121,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { before(async () => { response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-node/transactions/charts/latency`, + pathname: `/internal/apm/services/opbeans-node/transactions/charts/latency`, query: { start, end, @@ -146,7 +146,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { before(async () => { response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-node/transactions/charts/latency`, + pathname: `/internal/apm/services/opbeans-node/transactions/charts/latency`, query: { start, end, @@ -176,7 +176,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { before(async () => { response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-node/transactions/charts/latency`, + pathname: `/internal/apm/services/opbeans-node/transactions/charts/latency`, query: { latencyAggregationType: 'avg', transactionType: 'request', @@ -217,7 +217,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { before(async () => { response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-node/transactions/charts/latency`, + pathname: `/internal/apm/services/opbeans-node/transactions/charts/latency`, query: { start, end, @@ -257,7 +257,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { before(async () => { response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/transactions/charts/latency`, + pathname: `/internal/apm/services/opbeans-java/transactions/charts/latency`, query: { start, end, @@ -279,7 +279,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { before(async () => { response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-python/transactions/charts/latency`, + pathname: `/internal/apm/services/opbeans-python/transactions/charts/latency`, query: { start, end, @@ -319,7 +319,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { before(async () => { response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/transactions/charts/latency`, + pathname: `/internal/apm/services/opbeans-java/transactions/charts/latency`, query: { start, end, diff --git a/x-pack/test/apm_api_integration/tests/transactions/trace_samples.ts b/x-pack/test/apm_api_integration/tests/transactions/trace_samples.ts index fca9222e69bd00..19e75ff08fec21 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/trace_samples.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/trace_samples.ts @@ -17,7 +17,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const archiveName = 'apm_8.0.0'; const metadata = archives_metadata[archiveName]; - const url = `/api/apm/services/opbeans-java/transactions/traces/samples?${qs.stringify({ + const url = `/internal/apm/services/opbeans-java/transactions/traces/samples?${qs.stringify({ environment: 'ENVIRONMENT_ALL', kuery: '', start: metadata.start, diff --git a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_detailed_statistics.ts b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_detailed_statistics.ts index 84d7a2986ecb3f..add954f490db10 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_detailed_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_detailed_statistics.ts @@ -16,7 +16,7 @@ import { registry } from '../../common/registry'; import { removeEmptyCoordinates, roundNumber } from '../../utils'; type TransactionsGroupsDetailedStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/transactions/groups/detailed_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics'>; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('legacySupertestAsApmReadUser'); @@ -32,7 +32,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('handles the empty state', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/transactions/groups/detailed_statistics`, + pathname: `/internal/apm/services/opbeans-java/transactions/groups/detailed_statistics`, query: { start, end, @@ -59,7 +59,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns the correct data', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/transactions/groups/detailed_statistics`, + pathname: `/internal/apm/services/opbeans-java/transactions/groups/detailed_statistics`, query: { start, end, @@ -113,7 +113,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns the correct data for latency aggregation 99th percentile', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/transactions/groups/detailed_statistics`, + pathname: `/internal/apm/services/opbeans-java/transactions/groups/detailed_statistics`, query: { start, end, @@ -161,7 +161,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns empty when transaction name is not found', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/transactions/groups/detailed_statistics`, + pathname: `/internal/apm/services/opbeans-java/transactions/groups/detailed_statistics`, query: { start, end, @@ -185,7 +185,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { before(async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/transactions/groups/detailed_statistics`, + pathname: `/internal/apm/services/opbeans-java/transactions/groups/detailed_statistics`, query: { numBuckets: 20, transactionType: 'request', diff --git a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_main_statistics.ts b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_main_statistics.ts index ffdbf35992d7cd..7664d28271e14b 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_main_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_main_statistics.ts @@ -14,7 +14,7 @@ import archives from '../../common/fixtures/es_archiver/archives_metadata'; import { registry } from '../../common/registry'; type TransactionsGroupsPrimaryStatistics = - APIReturnType<'GET /api/apm/services/{serviceName}/transactions/groups/main_statistics'>; + APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics'>; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('legacySupertestAsApmReadUser'); @@ -29,7 +29,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('handles the empty state', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/transactions/groups/main_statistics`, + pathname: `/internal/apm/services/opbeans-java/transactions/groups/main_statistics`, query: { start, end, @@ -57,7 +57,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns the correct data', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/transactions/groups/main_statistics`, + pathname: `/internal/apm/services/opbeans-java/transactions/groups/main_statistics`, query: { start, end, @@ -132,7 +132,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns the correct data for latency aggregation 99th percentile', async () => { const response = await supertest.get( url.format({ - pathname: `/api/apm/services/opbeans-java/transactions/groups/main_statistics`, + pathname: `/internal/apm/services/opbeans-java/transactions/groups/main_statistics`, query: { start, end, diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_overrides.ts b/x-pack/test/fleet_api_integration/apis/epm/install_overrides.ts index 34917528560bd5..02820f85e8ee59 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_overrides.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_overrides.ts @@ -121,6 +121,11 @@ export default function (providerContext: FtrProviderContext) { lifecycle: { name: 'overridden by user', }, + mapping: { + total_fields: { + limit: '10000', + }, + }, number_of_shards: '3', }, }, diff --git a/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts b/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts index a8ccb5e301d5bc..f46dcdb761e6dc 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts @@ -220,6 +220,11 @@ export default function (providerContext: FtrProviderContext) { index: { lifecycle: { name: 'reference2' }, codec: 'best_compression', + mapping: { + total_fields: { + limit: '10000', + }, + }, query: { default_field: ['logs_test_name', 'new_field_name'], }, diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index 99bdb20580ce84..3c27aaeffa7112 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -98,8 +98,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(res.text).to.be(`\n`); }); - // FIXME: https://github.com/elastic/kibana/issues/112186 - it.skip('generates a large export', async () => { + it('generates a large export', async () => { const fromTime = 'Apr 27, 2019 @ 23:56:51.374'; const toTime = 'Aug 23, 2019 @ 16:18:51.821'; await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); @@ -112,7 +111,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // match file length, the beginning and the end of the csv file contents const { text: csvFile } = await getReport(); - expect(csvFile.length).to.be(4954749); + expect(csvFile.length).to.be(5093456); expectSnapshot(csvFile.slice(0, 5000)).toMatch(); expectSnapshot(csvFile.slice(-5000)).toMatch(); }); diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/trained_models.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/trained_models.ts index 43130651cb121d..b302e0bfb1140b 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/trained_models.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/trained_models.ts @@ -12,8 +12,8 @@ export default function ({ getService }: FtrProviderContext) { describe('trained models', function () { before(async () => { - await ml.trainedModels.createdTestTrainedModels('classification', 15); - await ml.trainedModels.createdTestTrainedModels('regression', 15); + await ml.trainedModels.createTestTrainedModels('classification', 15, true); + await ml.trainedModels.createTestTrainedModels('regression', 15); await ml.securityUI.loginAsMlPowerUser(); await ml.navigation.navigateToTrainedModels(); }); @@ -22,10 +22,116 @@ export default function ({ getService }: FtrProviderContext) { await ml.api.cleanMlIndices(); }); + // 'Created at' will be different on each run, + // so we will just assert that the value is in the expected timestamp format. + const builtInModelData = { + modelId: 'lang_ident_model_1', + description: 'Model used for identifying language from arbitrary input text.', + modelTypes: ['classification', 'built-in'], + }; + + const modelWithPipelineData = { + modelId: 'dfa_classification_model_n_0', + description: '', + modelTypes: ['classification'], + }; + + const modelWithoutPipelineData = { + modelId: 'dfa_regression_model_n_0', + description: '', + modelTypes: ['regression'], + }; + it('renders trained models list', async () => { - await ml.trainedModels.assertRowsNumberPerPage(10); + await ml.testExecution.logTestStep( + 'should display the stats bar with the total number of models' + ); // +1 because of the built-in model await ml.trainedModels.assertStats(31); + + await ml.testExecution.logTestStep('should display the table'); + await ml.trainedModels.assertTableExists(); + await ml.trainedModels.assertRowsNumberPerPage(10); + }); + + it('displays the built-in model and no actions are enabled', async () => { + await ml.testExecution.logTestStep('should display the model in the table'); + await ml.trainedModelsTable.filterWithSearchString(builtInModelData.modelId, 1); + + await ml.testExecution.logTestStep('displays expected row values for the model in the table'); + await ml.trainedModelsTable.assertModelsRowFields(builtInModelData.modelId, { + id: builtInModelData.modelId, + description: builtInModelData.description, + modelTypes: builtInModelData.modelTypes, + }); + + await ml.testExecution.logTestStep( + 'should not show collapsed actions menu for the model in the table' + ); + await ml.trainedModelsTable.assertModelCollapsedActionsButtonExists( + builtInModelData.modelId, + false + ); + + await ml.testExecution.logTestStep( + 'should not show delete action for the model in the table' + ); + await ml.trainedModelsTable.assertModelDeleteActionButtonExists( + builtInModelData.modelId, + false + ); + }); + + it('displays a model with an ingest pipeline and delete action is disabled', async () => { + await ml.testExecution.logTestStep('should display the model in the table'); + await ml.trainedModelsTable.filterWithSearchString(modelWithPipelineData.modelId, 1); + + await ml.testExecution.logTestStep('displays expected row values for the model in the table'); + await ml.trainedModelsTable.assertModelsRowFields(modelWithPipelineData.modelId, { + id: modelWithPipelineData.modelId, + description: modelWithPipelineData.description, + modelTypes: modelWithPipelineData.modelTypes, + }); + + await ml.testExecution.logTestStep( + 'should show disabled delete action for the model in the table' + ); + + await ml.trainedModelsTable.assertModelDeleteActionButtonEnabled( + modelWithPipelineData.modelId, + false + ); + }); + + it('displays a model without an ingest pipeline and model can be deleted', async () => { + await ml.testExecution.logTestStep('should display the model in the table'); + await ml.trainedModelsTable.filterWithSearchString(modelWithoutPipelineData.modelId, 1); + + await ml.testExecution.logTestStep('displays expected row values for the model in the table'); + await ml.trainedModelsTable.assertModelsRowFields(modelWithoutPipelineData.modelId, { + id: modelWithoutPipelineData.modelId, + description: modelWithoutPipelineData.description, + modelTypes: modelWithoutPipelineData.modelTypes, + }); + + await ml.testExecution.logTestStep( + 'should show enabled delete action for the model in the table' + ); + + await ml.trainedModelsTable.assertModelDeleteActionButtonEnabled( + modelWithoutPipelineData.modelId, + true + ); + + await ml.testExecution.logTestStep('should show the delete modal'); + await ml.trainedModelsTable.clickDeleteAction(modelWithoutPipelineData.modelId); + + await ml.testExecution.logTestStep('should delete the model'); + await ml.trainedModelsTable.confirmDeleteModel(); + await ml.trainedModelsTable.assertModelDisplayedInTable( + modelWithoutPipelineData.modelId, + false + ); }); }); } diff --git a/x-pack/test/functional/apps/uptime/certificates.ts b/x-pack/test/functional/apps/uptime/certificates.ts index 610f07c1837821..49298ec3a6f934 100644 --- a/x-pack/test/functional/apps/uptime/certificates.ts +++ b/x-pack/test/functional/apps/uptime/certificates.ts @@ -18,7 +18,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); const es = getService('es'); - describe('certificates', function () { + // FLAKY https://github.com/elastic/kibana/issues/114261 + describe.skip('certificates', function () { describe('empty certificates', function () { before(async () => { await esArchiver.load(BLANK_INDEX_PATH); diff --git a/x-pack/test/functional/services/ml/api.ts b/x-pack/test/functional/services/ml/api.ts index 7add4a024b469b..abde3bf365384d 100644 --- a/x-pack/test/functional/services/ml/api.ts +++ b/x-pack/test/functional/services/ml/api.ts @@ -981,11 +981,11 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { .expect(200) .then((res: any) => res.body); - log.debug('> Trained model crated'); + log.debug('> Trained model created'); return model; }, - async createdTestTrainedModels( + async createTestTrainedModels( modelType: ModelType, count: number = 10, withIngestPipelines = false diff --git a/x-pack/test/functional/services/ml/index.ts b/x-pack/test/functional/services/ml/index.ts index e12289c6306963..d50ec371d7c23d 100644 --- a/x-pack/test/functional/services/ml/index.ts +++ b/x-pack/test/functional/services/ml/index.ts @@ -51,6 +51,7 @@ import { SwimLaneProvider } from './swim_lane'; import { MachineLearningDashboardJobSelectionTableProvider } from './dashboard_job_selection_table'; import { MachineLearningDashboardEmbeddablesProvider } from './dashboard_embeddables'; import { TrainedModelsProvider } from './trained_models'; +import { TrainedModelsTableProvider } from './trained_models_table'; import { MachineLearningJobAnnotationsProvider } from './job_annotations_table'; export function MachineLearningProvider(context: FtrProviderContext) { @@ -121,6 +122,7 @@ export function MachineLearningProvider(context: FtrProviderContext) { const alerting = MachineLearningAlertingProvider(context, commonUI); const swimLane = SwimLaneProvider(context); const trainedModels = TrainedModelsProvider(context, api, commonUI); + const trainedModelsTable = TrainedModelsTableProvider(context); return { anomaliesTable, @@ -168,5 +170,6 @@ export function MachineLearningProvider(context: FtrProviderContext) { testExecution, testResources, trainedModels, + trainedModelsTable, }; } diff --git a/x-pack/test/functional/services/ml/trained_models.ts b/x-pack/test/functional/services/ml/trained_models.ts index 7a1fa1714ca143..a15ec9fb1ecd65 100644 --- a/x-pack/test/functional/services/ml/trained_models.ts +++ b/x-pack/test/functional/services/ml/trained_models.ts @@ -18,15 +18,26 @@ export function TrainedModelsProvider( mlCommonUI: MlCommonUI ) { const testSubjects = getService('testSubjects'); + const retry = getService('retry'); return { - async createdTestTrainedModels(modelType: ModelType, count: number = 10) { - await mlApi.createdTestTrainedModels(modelType, count); + async createTestTrainedModels( + modelType: ModelType, + count: number = 10, + withIngestPipelines = false + ) { + await mlApi.createTestTrainedModels(modelType, count, withIngestPipelines); }, async assertStats(expectedTotalCount: number) { - const actualStats = await testSubjects.getVisibleText('mlInferenceModelsStatsBar'); - expect(actualStats).to.eql(`Total trained models: ${expectedTotalCount}`); + await retry.tryForTime(5 * 1000, async () => { + const actualStats = await testSubjects.getVisibleText('mlInferenceModelsStatsBar'); + expect(actualStats).to.eql(`Total trained models: ${expectedTotalCount}`); + }); + }, + + async assertTableExists() { + await testSubjects.existOrFail('~mlModelsTable'); }, async assertRowsNumberPerPage(rowsNumber: 10 | 25 | 100) { diff --git a/x-pack/test/functional/services/ml/trained_models_table.ts b/x-pack/test/functional/services/ml/trained_models_table.ts new file mode 100644 index 00000000000000..11a97a4fed8fe0 --- /dev/null +++ b/x-pack/test/functional/services/ml/trained_models_table.ts @@ -0,0 +1,212 @@ +/* + * 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 expect from '@kbn/expect'; +import { ProvidedType } from '@kbn/test'; + +import { WebElementWrapper } from 'test/functional/services/lib/web_element_wrapper'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export interface TrainedModelRowData { + id: string; + description: string; + modelTypes: string[]; +} + +export type MlTrainedModelsTable = ProvidedType; + +export function TrainedModelsTableProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + + return new (class ModelsTable { + public async parseModelsTable() { + const table = await testSubjects.find('~mlModelsTable'); + const $ = await table.parseDomContent(); + const rows = []; + + for (const tr of $.findTestSubjects('~mlModelsTableRow').toArray()) { + const $tr = $(tr); + + const $types = $tr.findTestSubjects('mlModelType'); + const modelTypes = []; + for (const el of $types.toArray()) { + modelTypes.push($(el).text().trim()); + } + + const rowObject: { + id: string; + description: string; + modelTypes: string[]; + createdAt: string; + } = { + id: $tr + .findTestSubject('mlModelsTableColumnId') + .find('.euiTableCellContent') + .text() + .trim(), + description: $tr + .findTestSubject('mlModelsTableColumnDescription') + .find('.euiTableCellContent') + .text() + .trim(), + modelTypes, + createdAt: $tr + .findTestSubject('mlModelsTableColumnCreatedAt') + .find('.euiTableCellContent') + .text() + .trim(), + }; + + rows.push(rowObject); + } + + return rows; + } + + public rowSelector(modelId: string, subSelector?: string) { + const row = `~mlModelsTable > ~row-${modelId}`; + return !subSelector ? row : `${row} > ${subSelector}`; + } + + public async waitForRefreshButtonLoaded() { + await testSubjects.existOrFail('~mlAnalyticsRefreshListButton', { timeout: 10 * 1000 }); + await testSubjects.existOrFail('mlAnalyticsRefreshListButton loaded', { timeout: 30 * 1000 }); + } + + public async refreshModelsTable() { + await this.waitForRefreshButtonLoaded(); + await testSubjects.click('~mlAnalyticsRefreshListButton'); + await this.waitForRefreshButtonLoaded(); + await this.waitForModelsToLoad(); + } + + public async waitForModelsToLoad() { + await testSubjects.existOrFail('~mlModelsTable', { timeout: 60 * 1000 }); + await testSubjects.existOrFail('mlModelsTable loaded', { timeout: 30 * 1000 }); + } + + async getModelsSearchInput(): Promise { + const tableListContainer = await testSubjects.find('mlModelsTableContainer'); + return await tableListContainer.findByClassName('euiFieldSearch'); + } + + public async assertModelsSearchInputValue(expectedSearchValue: string) { + const searchBarInput = await this.getModelsSearchInput(); + const actualSearchValue = await searchBarInput.getAttribute('value'); + expect(actualSearchValue).to.eql( + expectedSearchValue, + `Trained models search input value should be '${expectedSearchValue}' (got '${actualSearchValue}')` + ); + } + + public async filterWithSearchString(filter: string, expectedRowCount: number = 1) { + await this.waitForModelsToLoad(); + const searchBarInput = await this.getModelsSearchInput(); + await searchBarInput.clearValueWithKeyboard(); + await searchBarInput.type(filter); + await this.assertModelsSearchInputValue(filter); + + const rows = await this.parseModelsTable(); + const filteredRows = rows.filter((row) => row.id === filter); + expect(filteredRows).to.have.length( + expectedRowCount, + `Filtered trained models table should have ${expectedRowCount} row(s) for filter '${filter}' (got matching items '${filteredRows}')` + ); + } + + public async assertModelDisplayedInTable(modelId: string, shouldBeDisplayed: boolean) { + await retry.tryForTime(5 * 1000, async () => { + await this.filterWithSearchString(modelId, shouldBeDisplayed === true ? 1 : 0); + }); + } + + public async assertModelsRowFields(modelId: string, expectedRow: TrainedModelRowData) { + await this.refreshModelsTable(); + const rows = await this.parseModelsTable(); + const modelRow = rows.filter((row) => row.id === modelId)[0]; + expect(modelRow.id).to.eql( + expectedRow.id, + `Expected trained model row ID to be '${expectedRow.id}' (got '${modelRow.id}')` + ); + expect(modelRow.description).to.eql( + expectedRow.description, + `Expected trained model row description to be '${expectedRow.description}' (got '${modelRow.description}')` + ); + expect(modelRow.modelTypes.sort()).to.eql( + expectedRow.modelTypes.sort(), + `Expected trained model row types to be '${JSON.stringify( + expectedRow.modelTypes + )}' (got '${JSON.stringify(modelRow.modelTypes)}')` + ); + // 'Created at' will be different on each run, + // so we will just assert that the value is in the expected timestamp format. + expect(modelRow.createdAt).to.match( + /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/, + `Expected trained model row created at time to have same format as '2019-12-05 12:28:34' (got '${modelRow.createdAt}')` + ); + } + + public async assertModelCollapsedActionsButtonExists(modelId: string, expectedValue: boolean) { + const actionsExists = await testSubjects.exists( + this.rowSelector(modelId, 'euiCollapsedItemActionsButton') + ); + expect(actionsExists).to.eql( + expectedValue, + `Expected row collapsed actions menu button for trained model '${modelId}' to be ${ + expectedValue ? 'visible' : 'hidden' + } (got ${actionsExists ? 'visible' : 'hidden'})` + ); + } + + public async assertModelDeleteActionButtonExists(modelId: string, expectedValue: boolean) { + const actionsExists = await testSubjects.exists( + this.rowSelector(modelId, 'mlModelsTableRowDeleteAction') + ); + expect(actionsExists).to.eql( + expectedValue, + `Expected row delete action button for trained model '${modelId}' to be ${ + expectedValue ? 'visible' : 'hidden' + } (got ${actionsExists ? 'visible' : 'hidden'})` + ); + } + + public async assertModelDeleteActionButtonEnabled(modelId: string, expectedValue: boolean) { + await this.assertModelDeleteActionButtonExists(modelId, true); + const isEnabled = await testSubjects.isEnabled( + this.rowSelector(modelId, 'mlModelsTableRowDeleteAction') + ); + expect(isEnabled).to.eql( + expectedValue, + `Expected row delete action button for trained model '${modelId}' to be '${ + expectedValue ? 'enabled' : 'disabled' + }' (got '${isEnabled ? 'enabled' : 'disabled'}')` + ); + } + + public async assertDeleteModalExists() { + await testSubjects.existOrFail('mlModelsDeleteModal', { timeout: 60 * 1000 }); + } + + public async assertDeleteModalNotExists() { + await testSubjects.missingOrFail('mlModelsDeleteModal', { timeout: 60 * 1000 }); + } + + public async confirmDeleteModel() { + await retry.tryForTime(30 * 1000, async () => { + await this.assertDeleteModalExists(); + await testSubjects.click('mlModelsDeleteModalConfirmButton'); + await this.assertDeleteModalNotExists(); + }); + } + + public async clickDeleteAction(modelId: string) { + await testSubjects.click(this.rowSelector(modelId, 'mlModelsTableRowDeleteAction')); + await this.assertDeleteModalExists(); + } + })(); +} diff --git a/x-pack/test/security_api_integration/tests/anonymous/capabilities.ts b/x-pack/test/security_api_integration/tests/anonymous/capabilities.ts index 886fa6f3fe7e35..baa9e9ff419a47 100644 --- a/x-pack/test/security_api_integration/tests/anonymous/capabilities.ts +++ b/x-pack/test/security_api_integration/tests/anonymous/capabilities.ts @@ -19,7 +19,7 @@ export default function ({ getService }: FtrProviderContext) { async function getAnonymousCapabilities(spaceId?: string) { const apiResponse = await supertest - .get(`${spaceId ? `/s/${spaceId}` : ''}/internal/security_oss/anonymous_access/capabilities`) + .get(`${spaceId ? `/s/${spaceId}` : ''}/internal/security/anonymous_access/capabilities`) .expect(200); return Object.fromEntries( diff --git a/x-pack/test/security_solution_cypress/es_archives/risky_hosts/data.json b/x-pack/test/security_solution_cypress/es_archives/risky_hosts/data.json index 7327f0fc76897f..e42a13ab8d8a85 100644 --- a/x-pack/test/security_solution_cypress/es_archives/risky_hosts/data.json +++ b/x-pack/test/security_solution_cypress/es_archives/risky_hosts/data.json @@ -2,7 +2,7 @@ "type":"doc", "value":{ "id":"a4cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f", - "index":"ml_host_risk_score_latest", + "index":"ml_host_risk_score_latest_default", "source":{ "@timestamp":"2021-03-10T14:51:05.766Z", "risk_score":21, diff --git a/x-pack/test/security_solution_cypress/es_archives/risky_hosts/mappings.json b/x-pack/test/security_solution_cypress/es_archives/risky_hosts/mappings.json index 211c50f6baee27..f71c9cf8ed4c26 100644 --- a/x-pack/test/security_solution_cypress/es_archives/risky_hosts/mappings.json +++ b/x-pack/test/security_solution_cypress/es_archives/risky_hosts/mappings.json @@ -1,7 +1,7 @@ { "type": "index", "value": { - "index": "ml_host_risk_score_latest", + "index": "ml_host_risk_score_latest_default", "mappings": { "properties": { "@timestamp": { @@ -40,8 +40,8 @@ "settings": { "index": { "lifecycle": { - "name": "ml_host_risk_score_latest", - "rollover_alias": "ml_host_risk_score_latest" + "name": "ml_host_risk_score_latest_default", + "rollover_alias": "ml_host_risk_score_latest_default" }, "mapping": { "total_fields": { diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts index 3a49278bd21a89..8f5177fe14f43b 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts @@ -72,7 +72,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { return tableData; }; - describe('endpoint list', function () { + // FLAKY + // https://github.com/elastic/kibana/issues/114249 + // https://github.com/elastic/kibana/issues/114250 + describe.skip('endpoint list', function () { const sleep = (ms = 100) => new Promise((resolve) => setTimeout(resolve, ms)); let indexedData: IndexedHostsAndAlertsResponse; describe('when initially navigating to page', () => { diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts index 70d60ba5c1b67f..5ff206b8ad6764 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts @@ -15,7 +15,7 @@ import { export default function (providerContext: FtrProviderContext) { const { loadTestFile, getService } = providerContext; - describe('endpoint', function () { + describe.skip('endpoint', function () { const ingestManager = getService('ingestManager'); const log = getService('log'); const endpointTestResources = getService('endpointTestResources'); diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/trusted_apps_list.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/trusted_apps_list.ts index 52fb9b8fc85992..042a685d19ef81 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/trusted_apps_list.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/trusted_apps_list.ts @@ -16,7 +16,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const endpointTestResources = getService('endpointTestResources'); const policyTestResources = getService('policyTestResources'); - describe('When on the Trusted Apps list', function () { + // FLAKY + // https://github.com/elastic/kibana/issues/114308 + // https://github.com/elastic/kibana/issues/114309 + describe.skip('When on the Trusted Apps list', function () { let indexedData: IndexedHostsAndAlertsResponse; before(async () => { const endpointPackage = await policyTestResources.getEndpointPackage(); diff --git a/yarn.lock b/yarn.lock index 7e8596ced9e5a7..defff7a1df42c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -46,6 +46,13 @@ dependencies: "@babel/highlight" "^7.14.5" +"@babel/code-frame@^7.15.8": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.15.8.tgz#45990c47adadb00c03677baa89221f7cc23d2503" + integrity sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg== + dependencies: + "@babel/highlight" "^7.14.5" + "@babel/compat-data@^7.12.5", "@babel/compat-data@^7.12.7": version "7.12.7" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.12.7.tgz#9329b4782a7d6bbd7eef57e11addf91ee3ef1e41" @@ -119,20 +126,20 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.15.5": - version "7.15.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.5.tgz#f8ed9ace730722544609f90c9bb49162dc3bf5b9" - integrity sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg== +"@babel/core@^7.15.8": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.8.tgz#195b9f2bffe995d2c6c159e72fe525b4114e8c10" + integrity sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og== dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.15.4" + "@babel/code-frame" "^7.15.8" + "@babel/generator" "^7.15.8" "@babel/helper-compilation-targets" "^7.15.4" - "@babel/helper-module-transforms" "^7.15.4" + "@babel/helper-module-transforms" "^7.15.8" "@babel/helpers" "^7.15.4" - "@babel/parser" "^7.15.5" + "@babel/parser" "^7.15.8" "@babel/template" "^7.15.4" "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" + "@babel/types" "^7.15.6" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -140,10 +147,10 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/eslint-parser@^7.15.7": - version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.15.7.tgz#2dc3d0ff0ea22bb1e08d93b4eeb1149bf1c75f2d" - integrity sha512-yJkHyomClm6A2Xzb8pdAo4HzYMSXFn1O5zrCYvbFP0yQFvHueLedV8WiEno8yJOKStjUXzBZzJFeWQ7b3YMsqQ== +"@babel/eslint-parser@^7.15.8": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.15.8.tgz#8988660b59d739500b67d0585fd4daca218d9f11" + integrity sha512-fYP7QFngCvgxjUuw8O057SVH5jCXsbFFOoE77CFDcvzwBVgTOkMD/L4mIC5Ud1xf8chK/no2fRbSSn1wvNmKuQ== dependencies: eslint-scope "^5.1.1" eslint-visitor-keys "^2.1.0" @@ -174,6 +181,15 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@^7.15.8": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.8.tgz#fa56be6b596952ceb231048cf84ee499a19c0cd1" + integrity sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g== + dependencies: + "@babel/types" "^7.15.6" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.0.0", "@babel/helper-annotate-as-pure@^7.10.4", "@babel/helper-annotate-as-pure@^7.12.10": version "7.12.10" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz#54ab9b000e60a93644ce17b3f37d313aaf1d115d" @@ -405,6 +421,20 @@ "@babel/traverse" "^7.15.4" "@babel/types" "^7.15.6" +"@babel/helper-module-transforms@^7.15.8": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz#d8c0e75a87a52e374a8f25f855174786a09498b2" + integrity sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg== + dependencies: + "@babel/helper-module-imports" "^7.15.4" + "@babel/helper-replace-supers" "^7.15.4" + "@babel/helper-simple-access" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + "@babel/helper-validator-identifier" "^7.15.7" + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.6" + "@babel/helper-optimise-call-expression@^7.10.4", "@babel/helper-optimise-call-expression@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea" @@ -602,11 +632,16 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.9.tgz#ca34cb95e1c2dd126863a84465ae8ef66114be99" integrity sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw== -"@babel/parser@^7.15.4", "@babel/parser@^7.15.5", "@babel/parser@^7.15.7": +"@babel/parser@^7.15.4": version "7.15.7" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.7.tgz#0c3ed4a2eb07b165dfa85b3cc45c727334c4edae" integrity sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g== +"@babel/parser@^7.15.8": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.8.tgz#7bacdcbe71bdc3ff936d510c15dcea7cf0b99016" + integrity sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA== + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.15.4": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.15.4.tgz#dbdeabb1e80f622d9f0b583efb2999605e0a567e" @@ -625,10 +660,10 @@ "@babel/helper-remap-async-to-generator" "^7.12.1" "@babel/plugin-syntax-async-generators" "^7.8.0" -"@babel/plugin-proposal-async-generator-functions@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.4.tgz#f82aabe96c135d2ceaa917feb9f5fca31635277e" - integrity sha512-2zt2g5vTXpMC3OmK6uyjvdXptbhBXfA77XGrd3gh93zwG8lZYBLOBImiGBEG0RANu3JqKEACCz5CGk73OJROBw== +"@babel/plugin-proposal-async-generator-functions@^7.15.8": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.8.tgz#a3100f785fab4357987c4223ab1b02b599048403" + integrity sha512-2Z5F2R2ibINTc63mY7FLqGfEbmofrHU9FitJW1Q7aPaKFhiPvSq6QEt/BoWN5oME3GVyjcRuNNSRbb9LC0CSWA== dependencies: "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-remap-async-to-generator" "^7.15.4" @@ -1561,15 +1596,15 @@ resolve "^1.8.1" semver "^5.5.1" -"@babel/plugin-transform-runtime@^7.15.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.0.tgz#d3aa650d11678ca76ce294071fda53d7804183b3" - integrity sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw== +"@babel/plugin-transform-runtime@^7.15.8": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.8.tgz#9d15b1e94e1c7f6344f65a8d573597d93c6cd886" + integrity sha512-+6zsde91jMzzvkzuEA3k63zCw+tm/GvuuabkpisgbDMTPQsIMHllE3XczJFFtEHLjjhKQFZmGQVRdELetlWpVw== dependencies: - "@babel/helper-module-imports" "^7.14.5" + "@babel/helper-module-imports" "^7.15.4" "@babel/helper-plugin-utils" "^7.14.5" babel-plugin-polyfill-corejs2 "^0.2.2" - babel-plugin-polyfill-corejs3 "^0.2.2" + babel-plugin-polyfill-corejs3 "^0.2.5" babel-plugin-polyfill-regenerator "^0.2.2" semver "^6.3.0" @@ -1595,13 +1630,13 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" -"@babel/plugin-transform-spread@^7.14.6": - version "7.14.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz#6bd40e57fe7de94aa904851963b5616652f73144" - integrity sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag== +"@babel/plugin-transform-spread@^7.15.8": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.15.8.tgz#79d5aa27f68d700449b2da07691dfa32d2f6d468" + integrity sha512-/daZ8s2tNaRekl9YJa9X4bzjpeRZLt122cpgFnQPLGUe61PH8zMEBmYqKkW5xF5JUEh5buEGXJoQpqBmIbpmEQ== dependencies: "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.15.4" "@babel/plugin-transform-sticky-regex@^7.12.7", "@babel/plugin-transform-sticky-regex@^7.2.0": version "7.12.7" @@ -1819,17 +1854,17 @@ core-js-compat "^3.8.0" semver "^5.5.0" -"@babel/preset-env@^7.15.6": - version "7.15.6" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.6.tgz#0f3898db9d63d320f21b17380d8462779de57659" - integrity sha512-L+6jcGn7EWu7zqaO2uoTDjjMBW+88FXzV8KvrBl2z6MtRNxlsmUNRlZPaNNPUTgqhyC5DHNFk/2Jmra+ublZWw== +"@babel/preset-env@^7.15.8": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.8.tgz#f527ce5bcb121cd199f6b502bf23e420b3ff8dba" + integrity sha512-rCC0wH8husJgY4FPbHsiYyiLxSY8oMDJH7Rl6RQMknbN9oDDHhM9RDFvnGM2MgkbUJzSQB4gtuwygY5mCqGSsA== dependencies: "@babel/compat-data" "^7.15.0" "@babel/helper-compilation-targets" "^7.15.4" "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-validator-option" "^7.14.5" "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.15.4" - "@babel/plugin-proposal-async-generator-functions" "^7.15.4" + "@babel/plugin-proposal-async-generator-functions" "^7.15.8" "@babel/plugin-proposal-class-properties" "^7.14.5" "@babel/plugin-proposal-class-static-block" "^7.15.4" "@babel/plugin-proposal-dynamic-import" "^7.14.5" @@ -1884,7 +1919,7 @@ "@babel/plugin-transform-regenerator" "^7.14.5" "@babel/plugin-transform-reserved-words" "^7.14.5" "@babel/plugin-transform-shorthand-properties" "^7.14.5" - "@babel/plugin-transform-spread" "^7.14.6" + "@babel/plugin-transform-spread" "^7.15.8" "@babel/plugin-transform-sticky-regex" "^7.14.5" "@babel/plugin-transform-template-literals" "^7.14.5" "@babel/plugin-transform-typeof-symbol" "^7.14.5" @@ -1893,7 +1928,7 @@ "@babel/preset-modules" "^0.1.4" "@babel/types" "^7.15.6" babel-plugin-polyfill-corejs2 "^0.2.2" - babel-plugin-polyfill-corejs3 "^0.2.2" + babel-plugin-polyfill-corejs3 "^0.2.5" babel-plugin-polyfill-regenerator "^0.2.2" core-js-compat "^3.16.0" semver "^6.3.0" @@ -2933,10 +2968,10 @@ "@hapi/validate" "1.x.x" "@hapi/wreck" "17.x.x" -"@hapi/hapi@^20.2.0": - version "20.2.0" - resolved "https://registry.yarnpkg.com/@hapi/hapi/-/hapi-20.2.0.tgz#bf0eca9cc591e83f3d72d06a998d31be35d044a1" - integrity sha512-yPH/z8KvlSLV8lI4EuId9z595fKKk5n6YA7H9UddWYWsBXMcnCyoFmHtYq0PCV4sNgKLD6QW9e27R9V9Z9aqqw== +"@hapi/hapi@^20.2.1": + version "20.2.1" + resolved "https://registry.yarnpkg.com/@hapi/hapi/-/hapi-20.2.1.tgz#7482bc28757cb4671623a61bdb5ce920bffc8a2f" + integrity sha512-OXAU+yWLwkMfPFic+KITo+XPp6Oxpgc9WUH+pxXWcTIuvWbgco5TC/jS8UDvz+NFF5IzRgF2CL6UV/KLdQYUSQ== dependencies: "@hapi/accept" "^5.0.1" "@hapi/ammo" "^5.0.1" @@ -2966,11 +3001,16 @@ "@hapi/hoek" "9.x.x" "@hapi/validate" "1.x.x" -"@hapi/hoek@9.x.x", "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.0.4", "@hapi/hoek@^9.2.0": +"@hapi/hoek@9.x.x", "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.0.4": version "9.2.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.0.tgz#f3933a44e365864f4dad5db94158106d511e8131" integrity sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug== +"@hapi/hoek@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17" + integrity sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw== + "@hapi/inert@^6.0.4": version "6.0.4" resolved "https://registry.yarnpkg.com/@hapi/inert/-/inert-6.0.4.tgz#0544221eabc457110a426818358d006e70ff1f41" @@ -4690,13 +4730,13 @@ resolved "https://registry.yarnpkg.com/@redux-saga/types/-/types-1.1.0.tgz#0e81ce56b4883b4b2a3001ebe1ab298b84237204" integrity sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg== -"@reduxjs/toolkit@^1.5.1": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.5.1.tgz#05daa2f6eebc70dc18cd98a90421fab7fa565dc5" - integrity sha512-PngZKuwVZsd+mimnmhiOQzoD0FiMjqVks6ituO1//Ft5UEX5Ca9of13NEjo//pU22Jk7z/mdXVsmDfgsig1osA== +"@reduxjs/toolkit@^1.6.1": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.6.1.tgz#7bc83b47352a663bf28db01e79d17ba54b98ade9" + integrity sha512-pa3nqclCJaZPAyBhruQtiRwtTjottRrVJqziVZcWzI73i6L3miLTtUyWfauwv08HWtiXLx1xGyGt+yLFfW/d0A== dependencies: - immer "^8.0.1" - redux "^4.0.0" + immer "^9.0.1" + redux "^4.1.0" redux-thunk "^2.3.0" reselect "^4.0.0" @@ -8926,7 +8966,7 @@ babel-plugin-polyfill-corejs2@^0.2.2: "@babel/helper-define-polyfill-provider" "^0.2.2" semver "^6.1.1" -babel-plugin-polyfill-corejs3@^0.2.2: +babel-plugin-polyfill-corejs3@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.5.tgz#2779846a16a1652244ae268b1e906ada107faf92" integrity sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw== @@ -16729,11 +16769,16 @@ immediate@~3.0.5: resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= -immer@8.0.1, immer@^8.0.1: +immer@8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656" integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA== +immer@^9.0.1, immer@^9.0.6: + version "9.0.6" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.6.tgz#7a96bf2674d06c8143e327cbf73539388ddf1a73" + integrity sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ== + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -24725,13 +24770,12 @@ redux-thunks@^1.0.0: resolved "https://registry.yarnpkg.com/redux-thunks/-/redux-thunks-1.0.0.tgz#56e03b86d281a2664c884ab05c543d9ab1673658" integrity sha1-VuA7htKBomZMiEqwXFQ9mrFnNlg= -redux@^4.0.0, redux@^4.0.4, redux@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f" - integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w== +redux@^4.0.0, redux@^4.0.4, redux@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.1.tgz#76f1c439bb42043f985fbd9bf21990e60bd67f47" + integrity sha512-hZQZdDEM25UY2P493kPYuKqviVwZ58lEmGQNeQ+gXa+U0gYPUBf7NKYazbe3m+bs/DzM/ahN12DbF+NG8i0CWw== dependencies: - loose-envify "^1.4.0" - symbol-observable "^1.2.0" + "@babel/runtime" "^7.9.2" reflect.ownkeys@^0.2.0: version "0.2.0"