From 7a9b3dfeffdc470fd7bebca0128d34075cda6487 Mon Sep 17 00:00:00 2001 From: Elena Stoeva <59341489+ElenaStoeva@users.noreply.github.com> Date: Tue, 31 Oct 2023 10:53:55 +0000 Subject: [PATCH 01/12] [Painless lab] Improve contrast ratio between text and background color (#169705) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/elastic/kibana/issues/154425 ## Summary Hi @elastic/appex-sharedux team 👋 We received a [request](https://github.com/elastic/kibana/issues/154425) to fix the low contrast of some text in the Painless lab, which uses the Kibana React plugin's code editor. Here are the changes in the colours from this PR: Before | Improvement -- | -- `euiColorAccent` Ratio: 3.27:1 | `euiColorAccentText` Ratio: 4.68:1 `euiColorSuccess` Ratio: 2.25:1 | `euiColorSuccessText` Ratio: 4.81:1 `euiColorVis0` Ratio: 2.47:1 | `euiColorSuccessText` Ratio: 4.81:1 `euiColorPrimary` Ratio: 4.53:1 | `euiColorPrimaryText` Ratio: 4.94:1 `euiColorMediumShade` Ratio: 2.51:1 | `euiTextSubduedColor` Ratio: 4.85:1 `euiColorWarning` Ratio: 1.55:1 | `euiColorWarningText` Ratio: 5.34:1 `euiColorDanger` Ratio: 5.89:1 | `euiColorDangerText` Ratio: 5.89:1 **Before:** Screenshot 2023-10-24 at 16 42 00 **After:** Screenshot 2023-10-24 at 16 41 19 --- .../public/code_editor/editor_theme.ts | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/plugins/kibana_react/public/code_editor/editor_theme.ts b/src/plugins/kibana_react/public/code_editor/editor_theme.ts index 70d3267338ed..107b67322932 100644 --- a/src/plugins/kibana_react/public/code_editor/editor_theme.ts +++ b/src/plugins/kibana_react/public/code_editor/editor_theme.ts @@ -27,62 +27,62 @@ export function createTheme( foreground: euiTheme.euiColorDarkestShade, background: euiTheme.euiFormBackgroundColor, }, - { token: 'invalid', foreground: euiTheme.euiColorAccent }, + { token: 'invalid', foreground: euiTheme.euiColorAccentText }, { token: 'emphasis', fontStyle: 'italic' }, { token: 'strong', fontStyle: 'bold' }, - { token: 'variable', foreground: euiTheme.euiColorPrimary }, - { token: 'variable.predefined', foreground: euiTheme.euiColorSuccess }, - { token: 'constant', foreground: euiTheme.euiColorAccent }, - { token: 'comment', foreground: euiTheme.euiColorMediumShade }, - { token: 'number', foreground: euiTheme.euiColorAccent }, - { token: 'number.hex', foreground: euiTheme.euiColorAccent }, - { token: 'regexp', foreground: euiTheme.euiColorDanger }, - { token: 'annotation', foreground: euiTheme.euiColorMediumShade }, - { token: 'type', foreground: euiTheme.euiColorVis0 }, + { token: 'variable', foreground: euiTheme.euiColorPrimaryText }, + { token: 'variable.predefined', foreground: euiTheme.euiColorSuccessText }, + { token: 'constant', foreground: euiTheme.euiColorAccentText }, + { token: 'comment', foreground: euiTheme.euiTextSubduedColor }, + { token: 'number', foreground: euiTheme.euiColorAccentText }, + { token: 'number.hex', foreground: euiTheme.euiColorAccentText }, + { token: 'regexp', foreground: euiTheme.euiColorDangerText }, + { token: 'annotation', foreground: euiTheme.euiTextSubduedColor }, + { token: 'type', foreground: euiTheme.euiColorSuccessText }, { token: 'delimiter', foreground: euiTheme.euiTextSubduedColor }, { token: 'delimiter.html', foreground: euiTheme.euiColorDarkShade }, - { token: 'delimiter.xml', foreground: euiTheme.euiColorPrimary }, + { token: 'delimiter.xml', foreground: euiTheme.euiColorPrimaryText }, - { token: 'tag', foreground: euiTheme.euiColorDanger }, - { token: 'tag.id.jade', foreground: euiTheme.euiColorPrimary }, - { token: 'tag.class.jade', foreground: euiTheme.euiColorPrimary }, - { token: 'meta.scss', foreground: euiTheme.euiColorAccent }, - { token: 'metatag', foreground: euiTheme.euiColorSuccess }, - { token: 'metatag.content.html', foreground: euiTheme.euiColorDanger }, - { token: 'metatag.html', foreground: euiTheme.euiColorMediumShade }, - { token: 'metatag.xml', foreground: euiTheme.euiColorMediumShade }, + { token: 'tag', foreground: euiTheme.euiColorDangerText }, + { token: 'tag.id.jade', foreground: euiTheme.euiColorPrimaryText }, + { token: 'tag.class.jade', foreground: euiTheme.euiColorPrimaryText }, + { token: 'meta.scss', foreground: euiTheme.euiColorAccentText }, + { token: 'metatag', foreground: euiTheme.euiColorSuccessText }, + { token: 'metatag.content.html', foreground: euiTheme.euiColorDangerText }, + { token: 'metatag.html', foreground: euiTheme.euiTextSubduedColor }, + { token: 'metatag.xml', foreground: euiTheme.euiTextSubduedColor }, { token: 'metatag.php', fontStyle: 'bold' }, - { token: 'key', foreground: euiTheme.euiColorWarning }, - { token: 'string.key.json', foreground: euiTheme.euiColorDanger }, - { token: 'string.value.json', foreground: euiTheme.euiColorPrimary }, + { token: 'key', foreground: euiTheme.euiColorWarningText }, + { token: 'string.key.json', foreground: euiTheme.euiColorDangerText }, + { token: 'string.value.json', foreground: euiTheme.euiColorPrimaryText }, - { token: 'attribute.name', foreground: euiTheme.euiColorDanger }, - { token: 'attribute.name.css', foreground: euiTheme.euiColorSuccess }, - { token: 'attribute.value', foreground: euiTheme.euiColorPrimary }, - { token: 'attribute.value.number', foreground: euiTheme.euiColorWarning }, - { token: 'attribute.value.unit', foreground: euiTheme.euiColorWarning }, - { token: 'attribute.value.html', foreground: euiTheme.euiColorPrimary }, - { token: 'attribute.value.xml', foreground: euiTheme.euiColorPrimary }, + { token: 'attribute.name', foreground: euiTheme.euiColorDangerText }, + { token: 'attribute.name.css', foreground: euiTheme.euiColorSuccessText }, + { token: 'attribute.value', foreground: euiTheme.euiColorPrimaryText }, + { token: 'attribute.value.number', foreground: euiTheme.euiColorWarningText }, + { token: 'attribute.value.unit', foreground: euiTheme.euiColorWarningText }, + { token: 'attribute.value.html', foreground: euiTheme.euiColorPrimaryText }, + { token: 'attribute.value.xml', foreground: euiTheme.euiColorPrimaryText }, - { token: 'string', foreground: euiTheme.euiColorDanger }, - { token: 'string.html', foreground: euiTheme.euiColorPrimary }, - { token: 'string.sql', foreground: euiTheme.euiColorDanger }, - { token: 'string.yaml', foreground: euiTheme.euiColorPrimary }, + { token: 'string', foreground: euiTheme.euiColorDangerText }, + { token: 'string.html', foreground: euiTheme.euiColorPrimaryText }, + { token: 'string.sql', foreground: euiTheme.euiColorDangerText }, + { token: 'string.yaml', foreground: euiTheme.euiColorPrimaryText }, - { token: 'keyword', foreground: euiTheme.euiColorPrimary }, - { token: 'keyword.json', foreground: euiTheme.euiColorPrimary }, - { token: 'keyword.flow', foreground: euiTheme.euiColorWarning }, - { token: 'keyword.flow.scss', foreground: euiTheme.euiColorPrimary }, + { token: 'keyword', foreground: euiTheme.euiColorPrimaryText }, + { token: 'keyword.json', foreground: euiTheme.euiColorPrimaryText }, + { token: 'keyword.flow', foreground: euiTheme.euiColorWarningText }, + { token: 'keyword.flow.scss', foreground: euiTheme.euiColorPrimaryText }, // Monaco editor supports strikethrough font style only starting from 0.32.0. - { token: 'keyword.deprecated', foreground: euiTheme.euiColorAccent }, + { token: 'keyword.deprecated', foreground: euiTheme.euiColorAccentText }, { token: 'operator.scss', foreground: euiTheme.euiColorDarkShade }, - { token: 'operator.sql', foreground: euiTheme.euiColorMediumShade }, - { token: 'operator.swift', foreground: euiTheme.euiColorMediumShade }, - { token: 'predefined.sql', foreground: euiTheme.euiColorMediumShade }, + { token: 'operator.sql', foreground: euiTheme.euiTextSubduedColor }, + { token: 'operator.swift', foreground: euiTheme.euiTextSubduedColor }, + { token: 'predefined.sql', foreground: euiTheme.euiTextSubduedColor }, { token: 'text', foreground: euiTheme.euiTitleColor }, { token: 'label', foreground: euiTheme.euiColorVis9 }, From 36b584f83691d506734649056fb6203317bdba16 Mon Sep 17 00:00:00 2001 From: Giorgos Bamparopoulos Date: Tue, 31 Oct 2023 10:59:50 +0000 Subject: [PATCH 02/12] [Observability] Add manual quality gate for Observability and update the version of the agent (#167502) Adds a manual quality gate for Observability in the QA environment to execute manual tests. It also updates the version of the manual verification agent. --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../quality-gates/pipeline.tests-qa.yaml | 23 +++++++++++++++---- .../quality-gates/pipeline.tests-staging.yaml | 3 +-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml b/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml index c1ec8b4c79cc..0c622a57ca73 100644 --- a/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml +++ b/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml @@ -39,8 +39,21 @@ steps: - wait: ~ - - label: ":judge::seedling: Trigger Manual Tests Phase" - command: "make -C /agent trigger-manual-verification-phase" - if: build.branch == "main" - agents: - image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.2" + - group: "Kibana Release Manager" + steps: + - label: ":judge::seedling: Trigger Manual Tests Phase - Kibana Release Manager" + command: "make -C /agent trigger-manual-verification-phase" + env: + USE_GROUP_LABEL: true + agents: + image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.4" + + - group: "Observability" + steps: + - label: ":judge::seedling: Trigger Manual Tests Phase - Observability" + command: "make -C /agent trigger-manual-verification-phase" + env: + NOTIFICATION_APPENDIX: " please execute your manual testing plan." + USE_GROUP_LABEL: true + agents: + image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.4" diff --git a/.buildkite/pipelines/quality-gates/pipeline.tests-staging.yaml b/.buildkite/pipelines/quality-gates/pipeline.tests-staging.yaml index 907c0de29e63..c1f8b0d94e17 100644 --- a/.buildkite/pipelines/quality-gates/pipeline.tests-staging.yaml +++ b/.buildkite/pipelines/quality-gates/pipeline.tests-staging.yaml @@ -25,6 +25,5 @@ steps: - label: ":judge::seedling: Trigger Manual Tests Phase" command: "make -C /agent trigger-manual-verification-phase" - if: build.branch == "main" agents: - image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.2" + image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.4" From bc8ab0cbff135d6665915fd895628a496c3f31b2 Mon Sep 17 00:00:00 2001 From: Elena Stoeva <59341489+ElenaStoeva@users.noreply.github.com> Date: Tue, 31 Oct 2023 11:34:17 +0000 Subject: [PATCH 03/12] [Advanced Setting] Fix functional tests for Observability serverless project (#169923) Fixes https://github.com/elastic/kibana/issues/168266 ## Summary This PR fixes and unskips the Advanced settings functional tests for the Observability serverless project. The test was failing because it was trying to check if the `observability:apmAWSLambdaPriceFactor` setting field is rendered, but this field is of json-type and editor fields cannot be tested because they don't have their test subjects rendered, so we skip them. --- .../test_suites/common/management/advanced_settings.ts | 1 + .../functional/test_suites/observability/advanced_settings.ts | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/test_serverless/functional/test_suites/common/management/advanced_settings.ts b/x-pack/test_serverless/functional/test_suites/common/management/advanced_settings.ts index aad12001ed52..ecaaa774c5c4 100644 --- a/x-pack/test_serverless/functional/test_suites/common/management/advanced_settings.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/advanced_settings.ts @@ -21,6 +21,7 @@ const editorSettings = new Set([ settings.SECURITY_SOLUTION_TIME_DEFAULTS_ID, settings.SECURITY_SOLUTION_RULES_TABLE_REFRESH_ID, settings.SECURITY_SOLUTION_IP_REPUTATION_LINKS_ID, + settings.OBSERVABILITY_APM_AWS_LAMBDA_PRICE_FACTOR_ID, ]); export const isEditorFieldSetting = (settingId: string) => editorSettings.has(settingId); diff --git a/x-pack/test_serverless/functional/test_suites/observability/advanced_settings.ts b/x-pack/test_serverless/functional/test_suites/observability/advanced_settings.ts index 18719b5b906b..d6f2ef6502f2 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/advanced_settings.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/advanced_settings.ts @@ -16,8 +16,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const browser = getService('browser'); const retry = getService('retry'); - // Failing: See https://github.com/elastic/kibana/issues/168266 - describe.skip('Observability advanced settings', function () { + describe('Observability advanced settings', function () { before(async () => { await pageObjects.svlCommonPage.login(); await pageObjects.common.navigateToApp('settings'); From 41be61ad26e7dcdf56cc050e397a3972c7b4c7af Mon Sep 17 00:00:00 2001 From: Elena Stoeva <59341489+ElenaStoeva@users.noreply.github.com> Date: Tue, 31 Oct 2023 11:49:02 +0000 Subject: [PATCH 04/12] [Search Profiler] Improve text color contrast ratio (#169697) Closes https://github.com/elastic/kibana/issues/154424 ## Summary This PR improves the color contrast ratio of the text in Search profiler by replacing the text with `EuiEmptyPrompt` in both the empty state component and the loading state component. Screenshot 2023-10-30 at 10 58 42 Screenshot 2023-10-30 at 10 58 28 Screenshot 2023-10-30 at 10 58 35 Screenshot 2023-10-30 at 11 05 10 Note: https://github.com/elastic/kibana/issues/154424 also mentions that the tabs in Search profiler have low contrast ratio and I addressed this in https://github.com/elastic/kibana/issues/154424#issuecomment-1777693100. --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/application/components/_index.scss | 19 ------------------- .../empty_tree_placeholder.tsx | 13 +++++++------ .../profile_loading_placeholder.tsx | 11 ++++++----- 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/x-pack/plugins/searchprofiler/public/application/components/_index.scss b/x-pack/plugins/searchprofiler/public/application/components/_index.scss index f2fdb44e7175..9d6688a2d4d9 100644 --- a/x-pack/plugins/searchprofiler/public/application/components/_index.scss +++ b/x-pack/plugins/searchprofiler/public/application/components/_index.scss @@ -5,22 +5,3 @@ $badgeSize: $euiSize * 5.5; @import 'percentage_badge/percentage_badge'; @import 'profile_query_editor/profile_query_editor'; @import 'profile_tree/index'; - -.prfDevTool__main__emptyTreePlaceholder { - h1 { - font-size: $euiSizeL; - color: $euiColorMediumShade; - } - p { - font-size: $euiSize; - color: $euiColorMediumShade; - } - h1, - p { - cursor: default; - user-select: none; - } - // Slight offset from the top. - margin: 5% 0 auto; - text-align: center; -} diff --git a/x-pack/plugins/searchprofiler/public/application/components/empty_tree_placeholder/empty_tree_placeholder.tsx b/x-pack/plugins/searchprofiler/public/application/components/empty_tree_placeholder/empty_tree_placeholder.tsx index 671d067f19fd..a5e30220b613 100644 --- a/x-pack/plugins/searchprofiler/public/application/components/empty_tree_placeholder/empty_tree_placeholder.tsx +++ b/x-pack/plugins/searchprofiler/public/application/components/empty_tree_placeholder/empty_tree_placeholder.tsx @@ -6,25 +6,26 @@ */ import React from 'react'; -import { EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { EuiEmptyPrompt } from '@elastic/eui'; export const EmptyTreePlaceHolder = () => { return ( -
- - {/* TODO: translations */} + {i18n.translate('xpack.searchProfiler.emptyProfileTreeTitle', { defaultMessage: 'No queries to profile', })} + } + body={

{i18n.translate('xpack.searchProfiler.emptyProfileTreeDescription', { defaultMessage: 'Enter a query, click Profile, and see the results here.', })}

-
-
+ } + /> ); }; diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_loading_placeholder/profile_loading_placeholder.tsx b/x-pack/plugins/searchprofiler/public/application/components/profile_loading_placeholder/profile_loading_placeholder.tsx index 54c6c79d446f..e5bcfefc2f72 100644 --- a/x-pack/plugins/searchprofiler/public/application/components/profile_loading_placeholder/profile_loading_placeholder.tsx +++ b/x-pack/plugins/searchprofiler/public/application/components/profile_loading_placeholder/profile_loading_placeholder.tsx @@ -6,18 +6,19 @@ */ import React from 'react'; -import { EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { EuiEmptyPrompt } from '@elastic/eui'; + export const ProfileLoadingPlaceholder = () => { return ( -
- + {i18n.translate('xpack.searchProfiler.profilingLoaderText', { defaultMessage: 'Loading query profiles...', })} - -
+ } + /> ); }; From d26b3736ce4b25063647e7c50675c51ede5a41c3 Mon Sep 17 00:00:00 2001 From: Gloria Hornero Date: Tue, 31 Oct 2023 12:58:44 +0100 Subject: [PATCH 05/12] [Security Solution] Fixes problematic test (#170222) ## Summary After the merge of https://github.com/elastic/kibana/pull/169563 seems that there is a test still using resetKibana (I don't know the reason). In this PR we are fixing that. Execution in ESS: Screenshot 2023-10-31 at 12 46 55 Execution in Serverless: Screenshot 2023-10-31 at 12 49 14 --- .../cypress/e2e/header/search_bar.cy.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/header/search_bar.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/header/search_bar.cy.ts index 383a51592e91..a92e5aa1d93d 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/header/search_bar.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/header/search_bar.cy.ts @@ -25,18 +25,11 @@ import { waitForAllHostsToBeLoaded } from '../../tasks/hosts/all_hosts'; describe('SearchBar', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { - cy.task('esArchiverResetKibana'); - cy.task('esArchiverLoad', { archiveName: 'auditbeat' }); - login(); visitWithTimeRange(hostsUrl('allHosts')); waitForAllHostsToBeLoaded(); }); - afterEach(() => { - cy.task('esArchiverUnload', 'auditbeat'); - }); - it('adds correctly a filter to the global search bar', () => { openAddFilterPopover(); fillAddFilterForm(getHostIpFilter()); From 8868d08745c4fb760bb82d5a2fc2e3a60da67afb Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Tue, 31 Oct 2023 13:55:03 +0100 Subject: [PATCH 06/12] make `isInlineScriptingEnabled` resilient to ES errors (#170208) ## Summary Fix https://github.com/elastic/kibana/issues/163787 Change the way `isInlineScriptingEnabled` function to retry retryable errors from ES (similar to how the valid connection or migration ES calls do) --- .../index.ts | 1 + .../src/is_scripting_enabled.test.mocks.ts | 15 ++++ .../src/is_scripting_enabled.test.ts | 55 ++++++++++++++ .../src/is_scripting_enabled.ts | 47 ++++++++---- .../src/retryable_es_client_errors.test.ts | 73 +++++++++++++++++++ .../src/retryable_es_client_errors.ts | 40 ++++++++++ .../catch_retryable_es_client_errors.ts | 23 +----- 7 files changed, 220 insertions(+), 34 deletions(-) create mode 100644 packages/core/elasticsearch/core-elasticsearch-server-internal/src/is_scripting_enabled.test.mocks.ts create mode 100644 packages/core/elasticsearch/core-elasticsearch-server-internal/src/retryable_es_client_errors.test.ts create mode 100644 packages/core/elasticsearch/core-elasticsearch-server-internal/src/retryable_es_client_errors.ts diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/index.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/index.ts index 3d81cebf9dc8..983be835a8db 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-internal/index.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/index.ts @@ -30,4 +30,5 @@ export { CoreElasticsearchRouteHandlerContext } from './src/elasticsearch_route_ export { retryCallCluster, migrationRetryCallCluster } from './src/retry_call_cluster'; export { isInlineScriptingEnabled } from './src/is_scripting_enabled'; export { getCapabilitiesFromClient } from './src/get_capabilities'; +export { isRetryableEsClientError } from './src/retryable_es_client_errors'; export type { ClusterInfo } from './src/get_cluster_info'; diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/is_scripting_enabled.test.mocks.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/is_scripting_enabled.test.mocks.ts new file mode 100644 index 000000000000..99485dca9a58 --- /dev/null +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/is_scripting_enabled.test.mocks.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const isRetryableEsClientErrorMock = jest.fn(); + +jest.doMock('./retryable_es_client_errors', () => { + return { + isRetryableEsClientError: isRetryableEsClientErrorMock, + }; +}); diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/is_scripting_enabled.test.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/is_scripting_enabled.test.ts index d2922c0161c6..57d40936b824 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/is_scripting_enabled.test.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/is_scripting_enabled.test.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { isRetryableEsClientErrorMock } from './is_scripting_enabled.test.mocks'; import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { isInlineScriptingEnabled } from './is_scripting_enabled'; @@ -94,4 +95,58 @@ describe('isInlineScriptingEnabled', () => { expect(await isInlineScriptingEnabled({ client })).toEqual(false); }); + + describe('resiliency', () => { + beforeEach(() => { + isRetryableEsClientErrorMock.mockReset(); + }); + + const mockSuccessOnce = () => { + client.cluster.getSettings.mockResolvedValueOnce({ + transient: {}, + persistent: {}, + defaults: {}, + }); + }; + const mockErrorOnce = () => { + client.cluster.getSettings.mockResponseImplementationOnce(() => { + throw Error('ERR CON REFUSED'); + }); + }; + + it('retries the ES api call in case of retryable error', async () => { + isRetryableEsClientErrorMock.mockReturnValue(true); + + mockErrorOnce(); + mockSuccessOnce(); + + await expect(isInlineScriptingEnabled({ client, maxRetryDelay: 1 })).resolves.toEqual(true); + expect(client.cluster.getSettings).toHaveBeenCalledTimes(2); + }); + + it('throws in case of non-retryable error', async () => { + isRetryableEsClientErrorMock.mockReturnValue(false); + + mockErrorOnce(); + mockSuccessOnce(); + + await expect(isInlineScriptingEnabled({ client, maxRetryDelay: 0.1 })).rejects.toThrowError( + 'ERR CON REFUSED' + ); + }); + + it('retries up to `maxRetries` times', async () => { + isRetryableEsClientErrorMock.mockReturnValue(true); + + mockErrorOnce(); + mockErrorOnce(); + mockErrorOnce(); + mockSuccessOnce(); + + await expect( + isInlineScriptingEnabled({ client, maxRetryDelay: 0.1, maxRetries: 2 }) + ).rejects.toThrowError('ERR CON REFUSED'); + expect(client.cluster.getSettings).toHaveBeenCalledTimes(3); + }); + }); }); diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/is_scripting_enabled.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/is_scripting_enabled.ts index 6a3900229c0d..ca3ca5b5c59a 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/is_scripting_enabled.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/is_scripting_enabled.ts @@ -6,27 +6,48 @@ * Side Public License, v 1. */ +import { defer, map, retry, timer, firstValueFrom, throwError } from 'rxjs'; import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { isRetryableEsClientError } from './retryable_es_client_errors'; const scriptAllowedTypesKey = 'script.allowed_types'; export const isInlineScriptingEnabled = async ({ client, + maxRetries = 20, + maxRetryDelay = 64, }: { client: ElasticsearchClient; + maxRetries?: number; + maxRetryDelay?: number; }): Promise => { - const settings = await client.cluster.getSettings({ - include_defaults: true, - flat_settings: true, - }); + return firstValueFrom( + defer(() => { + return client.cluster.getSettings({ + include_defaults: true, + flat_settings: true, + }); + }).pipe( + retry({ + count: maxRetries, + delay: (error, retryIndex) => { + if (isRetryableEsClientError(error)) { + const retryDelay = 1000 * Math.min(Math.pow(2, retryIndex), maxRetryDelay); // 2s, 4s, 8s, 16s, 32s, 64s, 64s, 64s ... + return timer(retryDelay); + } else { + return throwError(error); + } + }, + }), + map((settings) => { + const scriptAllowedTypes: string[] = + settings.transient[scriptAllowedTypesKey] ?? + settings.persistent[scriptAllowedTypesKey] ?? + settings.defaults![scriptAllowedTypesKey] ?? + []; - // priority: transient -> persistent -> default - const scriptAllowedTypes: string[] = - settings.transient[scriptAllowedTypesKey] ?? - settings.persistent[scriptAllowedTypesKey] ?? - settings.defaults![scriptAllowedTypesKey] ?? - []; - - // when unspecified, the setting as a default `[]` value that means that both scriptings are allowed. - return scriptAllowedTypes.length === 0 || scriptAllowedTypes.includes('inline'); + return scriptAllowedTypes.length === 0 || scriptAllowedTypes.includes('inline'); + }) + ) + ); }; diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/retryable_es_client_errors.test.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/retryable_es_client_errors.test.ts new file mode 100644 index 000000000000..45015cece5b4 --- /dev/null +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/retryable_es_client_errors.test.ts @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { errors as esErrors } from '@elastic/elasticsearch'; +import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; +import { isRetryableEsClientError } from './retryable_es_client_errors'; + +describe('isRetryableEsClientError', () => { + describe('returns `false` for', () => { + test('non-retryable response errors', async () => { + const error = new esErrors.ResponseError( + elasticsearchClientMock.createApiResponse({ + body: { error: { type: 'cluster_block_exception' } }, + statusCode: 400, + }) + ); + + expect(isRetryableEsClientError(error)).toEqual(false); + }); + }); + + describe('returns `true` for', () => { + it('NoLivingConnectionsError', () => { + const error = new esErrors.NoLivingConnectionsError( + 'reason', + elasticsearchClientMock.createApiResponse() + ); + + expect(isRetryableEsClientError(error)).toEqual(true); + }); + + it('ConnectionError', () => { + const error = new esErrors.ConnectionError( + 'reason', + elasticsearchClientMock.createApiResponse() + ); + expect(isRetryableEsClientError(error)).toEqual(true); + }); + + it('TimeoutError', () => { + const error = new esErrors.TimeoutError( + 'reason', + elasticsearchClientMock.createApiResponse() + ); + expect(isRetryableEsClientError(error)).toEqual(true); + }); + + it('ResponseError of type snapshot_in_progress_exception', () => { + const error = new esErrors.ResponseError( + elasticsearchClientMock.createApiResponse({ + body: { error: { type: 'snapshot_in_progress_exception' } }, + }) + ); + expect(isRetryableEsClientError(error)).toEqual(true); + }); + + it.each([503, 401, 403, 408, 410, 429])('ResponseError with %p status code', (statusCode) => { + const error = new esErrors.ResponseError( + elasticsearchClientMock.createApiResponse({ + statusCode, + body: { error: { type: 'reason' } }, + }) + ); + + expect(isRetryableEsClientError(error)).toEqual(true); + }); + }); +}); diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/retryable_es_client_errors.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/retryable_es_client_errors.ts new file mode 100644 index 000000000000..2ba0ff20a273 --- /dev/null +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/retryable_es_client_errors.ts @@ -0,0 +1,40 @@ +/* + * 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 { errors as EsErrors } from '@elastic/elasticsearch'; + +const retryResponseStatuses = [ + 503, // ServiceUnavailable + 401, // AuthorizationException + 403, // AuthenticationException + 408, // RequestTimeout + 410, // Gone + 429, // TooManyRequests -> ES circuit breaker +]; + +/** + * Returns true if the given elasticsearch error should be retried + * by retry-based resiliency systems such as the SO migration, false otherwise. + */ +export const isRetryableEsClientError = (e: EsErrors.ElasticsearchClientError): boolean => { + if ( + e instanceof EsErrors.NoLivingConnectionsError || + e instanceof EsErrors.ConnectionError || + e instanceof EsErrors.TimeoutError || + (e instanceof EsErrors.ResponseError && + (retryResponseStatuses.includes(e?.statusCode!) || + // ES returns a 400 Bad Request when trying to close or delete an + // index while snapshots are in progress. This should have been a 503 + // so once https://github.com/elastic/elasticsearch/issues/65883 is + // fixed we can remove this. + e?.body?.error?.type === 'snapshot_in_progress_exception')) + ) { + return true; + } + return false; +}; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.ts index 74877c938642..965742a2abb8 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.ts @@ -8,15 +8,7 @@ import * as Either from 'fp-ts/lib/Either'; import { errors as EsErrors } from '@elastic/elasticsearch'; - -const retryResponseStatuses = [ - 503, // ServiceUnavailable - 401, // AuthorizationException - 403, // AuthenticationException - 408, // RequestTimeout - 410, // Gone - 429, // TooManyRequests -> ES circuit breaker -]; +import { isRetryableEsClientError } from '@kbn/core-elasticsearch-server-internal'; export interface RetryableEsClientError { type: 'retryable_es_client_error'; @@ -27,18 +19,7 @@ export interface RetryableEsClientError { export const catchRetryableEsClientErrors = ( e: EsErrors.ElasticsearchClientError ): Either.Either => { - if ( - e instanceof EsErrors.NoLivingConnectionsError || - e instanceof EsErrors.ConnectionError || - e instanceof EsErrors.TimeoutError || - (e instanceof EsErrors.ResponseError && - (retryResponseStatuses.includes(e?.statusCode!) || - // ES returns a 400 Bad Request when trying to close or delete an - // index while snapshots are in progress. This should have been a 503 - // so once https://github.com/elastic/elasticsearch/issues/65883 is - // fixed we can remove this. - e?.body?.error?.type === 'snapshot_in_progress_exception')) - ) { + if (isRetryableEsClientError(e)) { return Either.left({ type: 'retryable_es_client_error' as const, message: e?.message, From 508f30926495949e9d9b1f6505071aee1c511f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Tue, 31 Oct 2023 13:07:51 +0000 Subject: [PATCH 07/12] [Serverless nav] Update docs with panels API (#170221) --- .../src/project_navigation.ts | 6 +- .../serverless_projects_documentation.mdx | 150 ++++++++++++++++-- 2 files changed, 136 insertions(+), 20 deletions(-) diff --git a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts index e7c1689048b0..b879cf6f716d 100644 --- a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts +++ b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts @@ -83,11 +83,7 @@ interface NodeDefinitionBase { */ breadcrumbStatus?: 'hidden' | 'visible'; /** - * Optional status to for the side navigation. "hidden" and "visible" are self explanatory. - * The `renderAsItem` status is _only_ for group nodes (nodes with children declared or with - * the "nodeType" set to `group`) and allow to render the node as an "item" instead of the head of - * a group. This is usefull to have sub-pages declared in the tree that will correctly be mapped - * in the Breadcrumbs, but are not rendered in the side navigation. + * Optional status to indicate if the node should be hidden in the side nav (but still present in the navigation tree). * @default 'visible' */ sideNavStatus?: SideNavNodeStatus; diff --git a/packages/shared-ux/chrome/serverless_projects_documentation.mdx b/packages/shared-ux/chrome/serverless_projects_documentation.mdx index 498d2a0737f9..25727791e038 100644 --- a/packages/shared-ux/chrome/serverless_projects_documentation.mdx +++ b/packages/shared-ux/chrome/serverless_projects_documentation.mdx @@ -48,11 +48,11 @@ In the following sections, we will explore each of these building blocks in deta > Left Side Navigation is available in shared_ux storybook under the `Chrome/Navigation` section. You can explore the components and their properties there. > `yarn storybook shared_ux` -The left side navigation is a primary way for users to navigate through different sections of the project. It consists of a tree of navigation items that can be expanded and collapsed. Apart from the navigation tree it also supports special pre-built blocks like recently accessed items. The main part of the navigation tree is project's navigation: this is fully configured and supported by the project teams (e.g. Observability). We also provide pre-configured platform sections as presets that solutions can use as part of their navigation (e.g. `ml`, `analytics`). Solutions can customize those sections to their needs. +The left side navigation is a primary way for users to navigate through different sections of the project. It consists of a tree of navigation items that can be expanded/collapsed or opened in a side panel. Apart from the navigation tree it also supports special pre-built blocks like recently accessed items. The main part of the navigation tree is project's navigation: this is fully configured and supported by the project teams (e.g. Observability). We also provide pre-configured platform sections as presets that solutions can use as part of their navigation (e.g. `ml`, `analytics`). Solutions can customize those sections to their needs. There are two approaches to building the side navigation: -1. **Navigation tree definition**: Developers provide a navigation tree definition. This approach is recommended if the use case works with the existing building blocks. +1. **Navigation tree definition**: Developers provide a navigation tree definition. ~~This approach is recommended if the use case works with the existing building blocks.~~ :warning: We are planing in deprecating this approach, use the React components instead. 2. **React components**: Alternatively, we provide a set of pre-built components that can be used to construct the left side navigation. These components include: @@ -69,6 +69,8 @@ By leveraging these components, you can create a customized left side navigation ### Navigation Tree Definition +:warning: **Soon to be deprecated** :warning: - Use the React components instead. + Use the `NavigationTreeDefinition` interface to create your left side navigation using a tree definition. This interface allows you to define the complete navigation tree, including the **body** and **footer** of the navigation. #### Example @@ -109,6 +111,19 @@ const navigationTree: NavigationTreeDefinition = { }, ], }, + { + id: 'search', + title: 'Search', + renderAs: 'accordion', // This group will be rendered as an accordion + children: [ + { + link: 'foo', + }, + { + link: 'bar', + }, + ], + }, ], }, { @@ -126,6 +141,7 @@ const navigationTree: NavigationTreeDefinition = { children: [ { id: 'settings', + renderAs: 'accordion', children: [ { link: 'management', @@ -190,25 +206,41 @@ The `RootNavigationItemDefinition` is one of: - `GroupDefinition` - `RecentlyAccessedDefinition` +- `PresetDefinition` +- `ItemDefinition` + +All those interfaces extend the `NodeDefinition` which has the following **common properties**: + +### `NodeDefinition` + +| Property | Type | Description| +| -------------------- | -------------------------| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `id` | `Id` (extends `string`) | Optional ID of the navigation node.| +| `title` | `string` | Optional title of the navigation node. If not provided and a "link" is provided, the title will be the Deep link title.| +| `link` | `LinkId` | Optional App ID or deep link ID for the navigation node. [More about deep links](#deep-links)| +| `icon` | `string` | Optional icon for the navigation node. Note that not all navigation depths will render the icon.| +| `href` | `string` | Use `href` for absolute links only. Internal links should use "link".| +| `getIsActive` | `function` | Optional function to control the active state. This function is called whenever the location changes.| +| `sideNavStatus` | `'hidden'\|'visible'` | Optional status to indicate if the node should be hidden in the side nav (but still present in the navigation tree). | +| `breadcrumbStatus` | `'hidden'\|'visible'` | An optional flag to indicate if the breadcrumb should be hidden when this node is active. The default value is `'visible'`.| +| `spaceBefore` | `EuiThemeSize\|null` | Optional vertical space to add before this node. It defaults to `null` except for group node at **tree depth 1** where it defaults to `"m"`. | + ##### `GroupDefinition` The `GroupDefinition` interface represents a group of items in the side navigation. It extends the `NodeDefinition` interface and has the following additional properties: -| Property | Type | Description | +| Property | Type | Description| | -------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `type` | `'navGroup'` | Indicates that this item is a navigation group. | -| `defaultIsCollapsed` | `boolean \| undefined` | Determines if the group is initially collapsed or expanded. Use `undefined` (recommended) to open the group if any of its children nodes match the current URL, `false` to always open the group, or `true` to always collapse it. | -| `preset` | `NavigationGroupPreset` | A preset value for the group, such as `'analytics'`, `'devtools'`, `'ml'`, or `'management'`. | -| `id` | `Id` | Optional ID of the navigation node. | -| `title` | `string` | Optional title of the navigation node. If not provided and a "link" is provided, the title will be the Deep link title. | -| `link` | `LinkId` | Optional App ID or deep link ID for the navigation node. [More about deep links](#deep-links) | -| `cloudLink` | `CloudLinkId` | Optional cloud link ID for the navigation node. [More about cloud links](#cloud-links) | -| `icon` | `string` | Optional icon for the navigation node. Note that not all navigation depths will render the icon. | -| `children` | `NodeDefinition[]` | Optional children of the navigation node. | -| `href` | `string` | Use `href` for absolute links only. Internal links should use "link". | -| `getIsActive` | `function` | Optional function to control the active state. This function is called whenever the location changes. | -| `breadcrumbStatus` | `'hidden'\|'visible'` | An optional flag to indicate if the breadcrumb should be hidden when this node is active. The default value is `'visible'`. | +| `type` | `'navGroup'` | Indicates that this item is a navigation group.| +| `children` | `NodeDefinition[]` | Children of the group navigation node. This is recursive, groups can contain other groups. | +| `defaultIsCollapsed` | `boolean \| undefined` | Determines if the group is initially collapsed or expanded. Use `undefined` (recommended) to open the group if any of its children nodes match the current URL, `false` to always open the group, or `true` to always collapse it.| +| `cloudLink` | `CloudLinkId` | Optional cloud link ID for the navigation node. [More about cloud links](#cloud-links)| +| `renderAs` | `'block'\|'accordion'\|'panelOpener'\|'item'`| Property to indicate how the group should be rendered.
* `'block'`: this is the default, renders the group as a block of items.
* `'accordion'`: wraps the items in an `EuiAccordion`.
* `'panelOpener'`: renders as an item with a `link` (required) + an icon button to open a panel on the right of the side nav.
* `'item'`: renders the group as an item in the side nav. This is useful when you want to declare descendant links of a node that will be displayed in the breadcrumb as such but you don't want to render any of the `children` in the side nav. | +| `appendHorizontalRule` | `boolean` | Optional flag to indicate if a horizontal rule should be rendered after the node.
Note: this property is currently only available for group nodes in the navigation **panel** opening on the right of the side nav. | +| `isCollapsible` | `boolean` | Optional flag to indicate if the accordion is collapsible (when `renderAs` is set to `'accordion'`.| + + ##### `RecentlyAccessedDefinition` @@ -218,6 +250,94 @@ The `GroupDefinition` interface represents a group of items in the side navigati | `recentlyAccessed$` | `Observable` | An optional observable for recently accessed items. If not provided, the recently accessed items from the Chrome service will be used. | | `defaultIsCollapsed` | `boolean` | If set to `true`, the recently accessed list will be collapsed by default. The default value is `false`. | +##### `PresetDefinition` + +The `PresetDefinition` interface represents a group of items which are prepopulated based on a preset. It extends the `GroupDefinition` interface (without `children` as those are pre-defined) and has the following additional properties: + +| Property | Type | Description| +| -------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `type` | `'preset'` | Indicates that this item is a navigation group.| +| `preset` | `NavigationGroupPreset` | A preset value for the group, such as `'analytics'`, `'devtools'`, `'ml'`, or `'management'`.| | + +##### `ItemDefinition` + +The `GroupDefinition` interface represents a group of items in the side navigation. It extends the `NodeDefinition` interface and has the following additional properties: + + +| Property | Type | Description| +| -------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `type` | `'navItem'` | Indicates that this item is a navigation item.| +| `cloudLink` | `CloudLinkId` | Optional cloud link ID for the navigation node. [More about cloud links](#cloud-links)| +| `openInNewTab` | `boolean` | Optional flag to indicate if the target page should be opened in a new Browser tab.
Note: this property is currently only used in the navigation **panel** opening on the right of the side nav.| +| `withBadge` | `boolean` | Optional flag to indicate if a badge should be rendered next to the text.
Note: this property is currently only used in the navigation **panel** opening on the right of the side nav.| +| `badgeOptions` | `{ text?: string; }` | If `withBadge` is true, this object can be used to customize the badge. | + +### Panels + +As seen in the API above, the `renderAs` property can be used to render a group as a panel opener. This is useful when you want to display a group of links in the side navigation and display its content in a panel on the right of the side navigation. +The content of the panel can be auto-generaged (based on the group's children) or manually provided. + +#### Auto-generated panels + +When the panel content is auto-generated, the group's children will be rendered in the panel. Those `children` can be items or other groups (that render as `'block' (default) or `'accordion'`). +The panel will be opened when the user clicks on the group's icon button. The panel will be closed when the user clicks on the group's icon again or when the user clicks outside of the panel. + +#### Manually provided panels + +When the panel content is manually provided, the group's `children` are used for the navigation tree definition (and the breadcrumbs) but the actual UI content rendered inside the panel is provided through JSX. + +```tsx +// 1. Define the PanelContentProvider +// ----------------------------------- +const panelContentProvider: PanelContentProvider = (id: string) => { + // The full ID of the node icon button that was clicked is provided (e.g. "root.group1.itemA") + // You can use this ID to determine which panel content to render + + if (id === 'foo1') { + // Return the JSX to render in the panel for this node. + return { + content: ({ + /** Handler to close the panel */ + closePanel, + /** ChromeNavigationNode - The node that has been clicked in the main nav */ + selectedNode, + /** ChromeProjectNavigationNode[][] - Active nodes that match the current URL location */ + activeNodes, + }) => { + return ( +
+ This is a custom component to render in the panel. + closePanel()}>Close panel +
+ ); + }, + }; + } + + if (id === 'foo2') { + // If need be you can only customize the "Title" of the panel and leave the content + // to be auto-generated. + return { + title:
Custom title
, + }; + } + + // All other nodes content ids that haven't match will be auto-generated +}; + +// 2. Pass it to the or components +// -------------------------------------------------------------------- + + + + {...} + +; + +// or using +; +``` + ### React components If you need other navigation sections in your navigation you will need to use our React components. They have the same properties as seen above except the `unstyled` prop that we will detail below. From bf64c22717525fafb5946bd400cb3b70434e3f6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Tue, 31 Oct 2023 14:23:34 +0100 Subject: [PATCH 08/12] [APM] Simplify cleanup of alerts in API tests (#170111) --- .../test/apm_api_integration/configs/index.ts | 23 +++---- .../tests/alerts/anomaly_alert.spec.ts | 14 ++--- .../alerts/error_count_threshold.spec.ts | 22 +------ ...ate.ts => cleanup_rule_and_alert_state.ts} | 8 ++- .../tests/alerts/transaction_duration.spec.ts | 30 ++------- .../alerts/transaction_error_rate.spec.ts | 30 ++------- .../tests/anomalies/anomaly_charts.spec.ts | 63 ++++++++----------- 7 files changed, 56 insertions(+), 134 deletions(-) rename x-pack/test/apm_api_integration/tests/alerts/helpers/{cleanup_state.ts => cleanup_rule_and_alert_state.ts} (79%) diff --git a/x-pack/test/apm_api_integration/configs/index.ts b/x-pack/test/apm_api_integration/configs/index.ts index 2e45cca1c50a..cdefe3011e49 100644 --- a/x-pack/test/apm_api_integration/configs/index.ts +++ b/x-pack/test/apm_api_integration/configs/index.ts @@ -14,36 +14,33 @@ const apmDebugLogger = { appenders: ['console'], }; +const kibanaConfig = { + 'xpack.apm.forceSyntheticSource': 'true', + 'logging.loggers': [apmDebugLogger], + 'server.publicBaseUrl': 'http://mockedPublicBaseUrl', +}; + const apmFtrConfigs = { basic: { license: 'basic' as const, - kibanaConfig: { - 'xpack.apm.forceSyntheticSource': 'true', - 'logging.loggers': [apmDebugLogger], - 'server.publicBaseUrl': 'http://mockedPublicBaseUrl', - }, + kibanaConfig, }, trial: { license: 'trial' as const, - kibanaConfig: { - 'xpack.apm.forceSyntheticSource': 'true', - 'logging.loggers': [apmDebugLogger], - }, + kibanaConfig, }, rules: { license: 'trial' as const, kibanaConfig: { + ...kibanaConfig, 'xpack.ruleRegistry.write.enabled': 'true', - 'xpack.apm.forceSyntheticSource': 'true', - 'logging.loggers': [apmDebugLogger], }, }, cloud: { license: 'basic' as const, kibanaConfig: { + ...kibanaConfig, 'xpack.apm.agent.migrations.enabled': 'true', - 'xpack.apm.forceSyntheticSource': 'true', - 'logging.loggers': [apmDebugLogger], }, }, }; diff --git a/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts index 430cebb4d0c0..cae769750b4c 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts @@ -13,8 +13,9 @@ import { range } from 'lodash'; import { ML_ANOMALY_SEVERITY } from '@kbn/ml-anomaly-utils/anomaly_severity'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createAndRunApmMlJobs } from '../../common/utils/create_and_run_apm_ml_jobs'; -import { createApmRule, deleteApmRules } from './helpers/alerting_api_helper'; +import { createApmRule } from './helpers/alerting_api_helper'; import { waitForActiveRule } from './helpers/wait_for_active_rule'; +import { cleanupRuleAndAlertState } from './helpers/cleanup_rule_and_alert_state'; export default function ApiTest({ getService }: FtrProviderContext) { const registry = getService('registry'); @@ -69,14 +70,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); async function cleanup() { - try { - await synthtraceEsClient.clean(); - await deleteApmRules(supertest); - await ml.cleanMlIndices(); - logger.info('Completed cleaned up'); - } catch (e) { - logger.info('Could not cleanup', e); - } + await synthtraceEsClient.clean(); + await cleanupRuleAndAlertState({ es, supertest, logger }); + await ml.cleanMlIndices(); } describe('with ml jobs', () => { diff --git a/x-pack/test/apm_api_integration/tests/alerts/error_count_threshold.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/error_count_threshold.spec.ts index 73a6386ea1ed..1cfcbc165b17 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/error_count_threshold.spec.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/error_count_threshold.spec.ts @@ -14,16 +14,13 @@ import { omit } from 'lodash'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createApmRule, - deleteRuleById, - deleteAlertsByRuleId, fetchServiceInventoryAlertCounts, fetchServiceTabAlertCount, ApmAlertFields, createIndexConnector, - deleteActionConnector, getIndexAction, } from './helpers/alerting_api_helper'; -import { cleanupAllState } from './helpers/cleanup_state'; +import { cleanupRuleAndAlertState } from './helpers/cleanup_rule_and_alert_state'; import { waitForAlertsForRule } from './helpers/wait_for_alerts_for_rule'; import { waitForIndexConnectorResults } from './helpers/wait_for_index_connector_results'; import { waitForActiveRule } from './helpers/wait_for_active_rule'; @@ -55,8 +52,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { }; before(async () => { - cleanupAllState({ es, supertest }); - const opbeansJava = apm .service({ name: 'opbeans-java', environment: 'production', agentName: 'java' }) .instance('instance'); @@ -134,13 +129,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - try { - await deleteActionConnector({ supertest, es, actionId }); - await deleteRuleById({ supertest, ruleId }); - await deleteAlertsByRuleId({ es, ruleId }); - } catch (e) { - logger.info('Could not delete rule or action connector', e); - } + await cleanupRuleAndAlertState({ es, supertest, logger }); }); it('checks if rule is active', async () => { @@ -285,12 +274,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - try { - await deleteRuleById({ supertest, ruleId }); - await deleteAlertsByRuleId({ es, ruleId }); - } catch (e) { - logger.info('Could not delete rule', e); - } + await cleanupRuleAndAlertState({ es, supertest, logger }); }); it('produces one alert for the opbeans-php service', async () => { diff --git a/x-pack/test/apm_api_integration/tests/alerts/helpers/cleanup_state.ts b/x-pack/test/apm_api_integration/tests/alerts/helpers/cleanup_rule_and_alert_state.ts similarity index 79% rename from x-pack/test/apm_api_integration/tests/alerts/helpers/cleanup_state.ts rename to x-pack/test/apm_api_integration/tests/alerts/helpers/cleanup_rule_and_alert_state.ts index 243ca1f71a36..144446a28b3d 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/helpers/cleanup_state.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/helpers/cleanup_rule_and_alert_state.ts @@ -6,6 +6,7 @@ */ import { Client } from '@elastic/elasticsearch'; +import { ToolingLog } from '@kbn/tooling-log'; import type { SuperTest, Test } from 'supertest'; import { clearKibanaApmEventLog, @@ -14,12 +15,14 @@ import { deleteActionConnectorIndex, } from './alerting_api_helper'; -export async function cleanupAllState({ +export async function cleanupRuleAndAlertState({ es, supertest, + logger, }: { es: Client; supertest: SuperTest; + logger: ToolingLog; }) { try { await Promise.all([ @@ -29,7 +32,6 @@ export async function cleanupAllState({ await clearKibanaApmEventLog(es), ]); } catch (e) { - // eslint-disable-next-line no-console - console.error(`An error occured while cleaning up the state: ${e}`); + logger.error(`An error occured while cleaning up the state: ${e}`); } } diff --git a/x-pack/test/apm_api_integration/tests/alerts/transaction_duration.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/transaction_duration.spec.ts index 84d34f29b7c8..bb8c9833bbc6 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/transaction_duration.spec.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/transaction_duration.spec.ts @@ -15,15 +15,11 @@ import { createApmRule, fetchServiceInventoryAlertCounts, fetchServiceTabAlertCount, - deleteAlertsByRuleId, - deleteRuleById, - clearKibanaApmEventLog, ApmAlertFields, createIndexConnector, getIndexAction, - deleteActionConnector, } from './helpers/alerting_api_helper'; -import { cleanupAllState } from './helpers/cleanup_state'; +import { cleanupRuleAndAlertState } from './helpers/cleanup_rule_and_alert_state'; import { waitForAlertsForRule } from './helpers/wait_for_alerts_for_rule'; import { waitForActiveRule } from './helpers/wait_for_active_rule'; import { waitForIndexConnectorResults } from './helpers/wait_for_index_connector_results'; @@ -49,8 +45,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when('transaction duration alert', { config: 'basic', archives: [] }, () => { before(async () => { - cleanupAllState({ es, supertest }); - const opbeansJava = apm .service({ name: 'opbeans-java', environment: 'production', agentName: 'java' }) .instance('instance'); @@ -77,12 +71,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - try { - await synthtraceEsClient.clean(); - await clearKibanaApmEventLog(es); - } catch (e) { - logger.info('Could not clear apm event log', e); - } + await synthtraceEsClient.clean(); }); describe('create rule for opbeans-java without kql filter', () => { @@ -111,13 +100,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - try { - await deleteActionConnector({ supertest, es, actionId }); - await deleteRuleById({ supertest, ruleId }); - await deleteAlertsByRuleId({ es, ruleId }); - } catch (e) { - logger.info('Could not delete rule or action connector', e); - } + await cleanupRuleAndAlertState({ es, supertest, logger }); }); it('checks if rule is active', async () => { @@ -229,12 +212,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - try { - await deleteAlertsByRuleId({ es, ruleId }); - await deleteRuleById({ supertest, ruleId }); - } catch (e) { - logger.info('Could not delete rule or action connector', e); - } + await cleanupRuleAndAlertState({ es, supertest, logger }); }); it('checks if rule is active', async () => { diff --git a/x-pack/test/apm_api_integration/tests/alerts/transaction_error_rate.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/transaction_error_rate.spec.ts index cdbe034b4c6a..056ee4e272d6 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/transaction_error_rate.spec.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/transaction_error_rate.spec.ts @@ -15,15 +15,11 @@ import { createApmRule, fetchServiceInventoryAlertCounts, fetchServiceTabAlertCount, - deleteAlertsByRuleId, - clearKibanaApmEventLog, - deleteRuleById, ApmAlertFields, getIndexAction, createIndexConnector, - deleteActionConnector, } from './helpers/alerting_api_helper'; -import { cleanupAllState } from './helpers/cleanup_state'; +import { cleanupRuleAndAlertState } from './helpers/cleanup_rule_and_alert_state'; import { waitForAlertsForRule } from './helpers/wait_for_alerts_for_rule'; import { waitForActiveRule } from './helpers/wait_for_active_rule'; import { waitForIndexConnectorResults } from './helpers/wait_for_index_connector_results'; @@ -38,8 +34,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when('transaction error rate alert', { config: 'basic', archives: [] }, () => { before(async () => { - cleanupAllState({ es, supertest }); - const opbeansJava = apm .service({ name: 'opbeans-java', environment: 'production', agentName: 'java' }) .instance('instance'); @@ -76,12 +70,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - try { - await synthtraceEsClient.clean(); - await clearKibanaApmEventLog(es); - } catch (e) { - logger.info('Could not clean up apm event log', e); - } + await synthtraceEsClient.clean(); }); describe('create rule without kql query', () => { @@ -121,13 +110,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - try { - await deleteActionConnector({ supertest, es, actionId }); - await deleteRuleById({ supertest, ruleId }); - await deleteAlertsByRuleId({ es, ruleId }); - } catch (e) { - logger.info('Could not delete rule or action connector', e); - } + await cleanupRuleAndAlertState({ es, supertest, logger }); }); it('checks if rule is active', async () => { @@ -250,12 +233,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - try { - await deleteRuleById({ supertest, ruleId }); - await deleteAlertsByRuleId({ es, ruleId }); - } catch (e) { - logger.info('Could not delete rule', e); - } + await cleanupRuleAndAlertState({ es, supertest, logger }); }); it('indexes alert document with all group-by fields', async () => { diff --git a/x-pack/test/apm_api_integration/tests/anomalies/anomaly_charts.spec.ts b/x-pack/test/apm_api_integration/tests/anomalies/anomaly_charts.spec.ts index 681443b69dff..05d7da0e2ca3 100644 --- a/x-pack/test/apm_api_integration/tests/anomalies/anomaly_charts.spec.ts +++ b/x-pack/test/apm_api_integration/tests/anomalies/anomaly_charts.spec.ts @@ -11,6 +11,7 @@ import { Environment } from '@kbn/apm-plugin/common/environment_rt'; import { apm, timerange } from '@kbn/apm-synthtrace-client'; import expect from '@kbn/expect'; import { last, omit, range } from 'lodash'; +import moment from 'moment'; import { ApmApiError } from '../../common/apm_api_supertest'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createAndRunApmMlJobs } from '../../common/utils/create_and_run_apm_ml_jobs'; @@ -21,9 +22,13 @@ export default function ApiTest({ getService }: FtrProviderContext) { const ml = getService('ml'); const es = getService('es'); const logger = getService('log'); - const synthtraceEsClient = getService('synthtraceEsClient'); + const start = moment().subtract(2, 'days'); + const end = moment(); + const spikeStart = moment().subtract(8, 'hours'); + const spikeEnd = moment().subtract(6, 'hours'); + async function statusOf(p: Promise<{ status: number }>) { try { const { status } = await p; @@ -38,14 +43,10 @@ export default function ApiTest({ getService }: FtrProviderContext) { function getAnomalyCharts( { - start, - end, transactionType, serviceName, environment, }: { - start: string; - end: string; transactionType: string; serviceName: string; environment: Environment; @@ -59,8 +60,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { serviceName, }, query: { - start, - end, + start: start.toISOString(), + end: end.toISOString(), transactionType, environment, }, @@ -77,8 +78,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { getAnomalyCharts({ serviceName: 'a', transactionType: 'request', - start: '2021-01-01T00:00:00.000Z', - end: '2021-01-01T00:15:00.000Z', environment: 'ENVIRONMENT_ALL', }) ); @@ -92,12 +91,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { 'fetching service anomalies with a trial license', { config: 'trial', archives: [] }, () => { - const start = '2021-01-01T00:00:00.000Z'; - const end = '2021-01-08T00:15:00.000Z'; - - const spikeStart = new Date('2021-01-03T00:00:00.000Z').getTime(); - const spikeEnd = new Date('2021-01-03T02:00:00.000Z').getTime(); - const NORMAL_DURATION = 100; const NORMAL_RATE = 1; @@ -110,13 +103,13 @@ export default function ApiTest({ getService }: FtrProviderContext) { .service({ name: 'b', environment: 'development', agentName: 'go' }) .instance('b'); - const events = timerange(new Date(start).getTime(), new Date(end).getTime()) + const events = timerange(start.valueOf(), end.valueOf()) .interval('1m') .rate(1) .generator((timestamp) => { - const isInSpike = timestamp >= spikeStart && timestamp < spikeEnd; + const isInSpike = timestamp >= spikeStart.valueOf() && timestamp < spikeEnd.valueOf(); const count = isInSpike ? 4 : NORMAL_RATE; - const duration = isInSpike ? 1000 : NORMAL_DURATION; + const duration = isInSpike ? 10000 : NORMAL_DURATION; const outcome = isInSpike ? 'failure' : 'success'; return [ @@ -139,9 +132,14 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - await synthtraceEsClient.clean(); + await cleanup(); }); + async function cleanup() { + await synthtraceEsClient.clean(); + await ml.cleanMlIndices(); + } + it('returns a 403 for a user without access to ML', async () => { expect( await statusOf( @@ -149,8 +147,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { { serviceName: 'a', transactionType: 'request', - start, - end, environment: 'ENVIRONMENT_ALL', }, apmApiClient.noMlAccessUser @@ -165,8 +161,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { getAnomalyCharts({ serviceName: 'a', transactionType: 'request', - start, - end, environment: 'ENVIRONMENT_ALL', }) ); @@ -185,17 +179,11 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - after(async () => { - await ml.cleanMlIndices(); - }); - it('returns a 200 for a user _with_ access to ML', async () => { const status = await statusOf( getAnomalyCharts({ serviceName: 'a', transactionType: 'request', - start, - end, environment: 'ENVIRONMENT_ALL', }) ); @@ -209,15 +197,13 @@ export default function ApiTest({ getService }: FtrProviderContext) { let latencySeries: ServiceAnomalyTimeseries | undefined; let throughputSeries: ServiceAnomalyTimeseries | undefined; let failureRateSeries: ServiceAnomalyTimeseries | undefined; - const endTimeMs = new Date(end).getTime(); + const endTimeMs = end.valueOf(); before(async () => { allAnomalyTimeseries = ( await getAnomalyCharts({ serviceName: 'a', transactionType: 'request', - start, - end, environment: 'ENVIRONMENT_ALL', }) ).body.allAnomalyTimeseries; @@ -246,12 +232,11 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect( allAnomalyTimeseries.every((spec) => - spec.bounds.every( - (bound) => bound.x >= new Date(start).getTime() && bound.x <= endTimeMs - ) + spec.bounds.every((bound) => bound.x >= start.valueOf() && bound.x <= endTimeMs) ) ); }); + it('returns model plots with latest bucket matching the end time', () => { expect(allAnomalyTimeseries.every((spec) => last(spec.bounds)?.x === endTimeMs)); }); @@ -310,19 +295,21 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect( latencyAnomalies?.every( - (anomaly) => anomaly.x >= spikeStart && (anomaly.actual ?? 0) > NORMAL_DURATION + (anomaly) => + anomaly.x >= spikeStart.valueOf() && (anomaly.actual ?? 0) > NORMAL_DURATION ) ); expect( throughputAnomalies?.every( - (anomaly) => anomaly.x >= spikeStart && (anomaly.actual ?? 0) > NORMAL_RATE + (anomaly) => + anomaly.x >= spikeStart.valueOf() && (anomaly.actual ?? 0) > NORMAL_RATE ) ); expect( failureRateAnomalies?.every( - (anomaly) => anomaly.x >= spikeStart && (anomaly.actual ?? 0) > 0 + (anomaly) => anomaly.x >= spikeStart.valueOf() && (anomaly.actual ?? 0) > 0 ) ); }); From 2e51c2517f52e2add1b2889bfc667c390d1f5441 Mon Sep 17 00:00:00 2001 From: Elastic Machine Date: Wed, 1 Nov 2023 01:09:28 +1100 Subject: [PATCH 09/12] [main] Sync bundled packages with Package Storage (#168698) Automated by https://internal-ci.elastic.co/job/package_storage/job/sync-bundled-packages-job/job/main/8080/ Co-authored-by: apmmachine --- fleet_packages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fleet_packages.json b/fleet_packages.json index 4640e150b1a3..ed422f0cfcb7 100644 --- a/fleet_packages.json +++ b/fleet_packages.json @@ -38,7 +38,7 @@ }, { "name": "fleet_server", - "version": "1.3.1" + "version": "1.4.0" }, { "name": "profiler_symbolizer", From a1bde01a8aafdbd0ca3bed418a3848e865801038 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 31 Oct 2023 15:26:43 +0100 Subject: [PATCH 10/12] [Serverless/Breadcrumbs] Use `EuiBreadcrumbs` instead of `EuiHeaderBreadcrumbs` (#169838) ## Summary fix https://github.com/elastic/kibana/issues/166593 https://github.com/elastic/kibana/assets/7784120/2569007b-92b6-47d0-a893-8747fbf17d2b - "Projects" link removed, now it is part of breadcrumb. This also makes the header more responsive as we get the flexibility from the breadcrumbs. - Added "View all projects" - Added "Manage project" link --- .../src/chrome_service.tsx | 8 +- .../src/project_navigation/breadcrumbs.tsx | 63 ++++++++++-- .../project_navigation/home_breadcrumbs.tsx | 25 ----- .../project_navigation_service.test.ts | 99 ++++++++++++++++--- .../project_navigation_service.ts | 29 ++++-- .../core-chrome-browser-internal/src/types.ts | 6 ++ .../src/ui/project/breadcrumbs.tsx | 47 +++++++++ .../src/ui/project/header.test.tsx | 14 --- .../src/ui/project/header.tsx | 31 +----- .../src/chrome_service.mock.ts | 1 + x-pack/plugins/serverless/public/plugin.tsx | 3 + .../page_objects/svl_common_navigation.ts | 3 - .../test_suites/observability/navigation.ts | 2 +- .../test_suites/search/navigation.ts | 2 +- .../test_suites/security/ftr/navigation.ts | 2 +- 15 files changed, 229 insertions(+), 106 deletions(-) delete mode 100644 packages/core/chrome/core-chrome-browser-internal/src/project_navigation/home_breadcrumbs.tsx create mode 100644 packages/core/chrome/core-chrome-browser-internal/src/ui/project/breadcrumbs.tsx diff --git a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx index 0e99c96656d5..eaa30238cde8 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx @@ -295,6 +295,11 @@ export class ChromeService { projectNavigation.setProjectName(projectName); }; + const setProjectUrl = (projectUrl: string) => { + validateChromeStyle(); + projectNavigation.setProjectUrl(projectUrl); + }; + const isIE = () => { const ua = window.navigator.userAgent; const msie = ua.indexOf('MSIE '); // IE 10 or older @@ -387,8 +392,6 @@ export class ChromeService { loadingCount$={http.getLoadingCount$()} headerBanner$={headerBanner$.pipe(takeUntil(this.stop$))} homeHref$={projectNavigation.getProjectHome$()} - projectsUrl$={projectNavigation.getProjectsUrl$()} - projectName$={projectNavigation.getProjectName$()} docLinks={docLinks} kibanaVersion={injectedMetadata.getKibanaVersion()} prependBasePath={http.basePath.prepend} @@ -521,6 +524,7 @@ export class ChromeService { project: { setHome: setProjectHome, setProjectsUrl, + setProjectUrl, setProjectName, setNavigation: setProjectNavigation, setSideNavComponent: setProjectSideNavComponent, diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/breadcrumbs.tsx b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/breadcrumbs.tsx index 1f0057e9670d..8bd690fba8a7 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/breadcrumbs.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/breadcrumbs.tsx @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { EuiContextMenuPanel, EuiContextMenuItem } from '@elastic/eui'; import { AppDeepLinkId, ChromeProjectBreadcrumb, @@ -13,15 +14,21 @@ import { ChromeSetProjectBreadcrumbsParams, ChromeBreadcrumb, } from '@kbn/core-chrome-browser'; -import { createHomeBreadcrumb } from './home_breadcrumbs'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import React from 'react'; export function buildBreadcrumbs({ - homeHref, + projectsUrl, + projectName, + projectUrl, projectBreadcrumbs, activeNodes, chromeBreadcrumbs, }: { - homeHref: string; + projectsUrl?: string; + projectName?: string; + projectUrl?: string; projectBreadcrumbs: { breadcrumbs: ChromeProjectBreadcrumb[]; params: ChromeSetProjectBreadcrumbsParams; @@ -29,12 +36,10 @@ export function buildBreadcrumbs({ chromeBreadcrumbs: ChromeBreadcrumb[]; activeNodes: ChromeProjectNavigationNode[][]; }): ChromeProjectBreadcrumb[] { - const homeBreadcrumb = createHomeBreadcrumb({ - homeHref, - }); + const rootCrumb = buildRootCrumb({ projectsUrl, projectName, projectUrl }); if (projectBreadcrumbs.params.absolute) { - return [homeBreadcrumb, ...projectBreadcrumbs.breadcrumbs]; + return [rootCrumb, ...projectBreadcrumbs.breadcrumbs]; } // breadcrumbs take the first active path @@ -52,7 +57,7 @@ export function buildBreadcrumbs({ // if there are project breadcrumbs set, use them if (projectBreadcrumbs.breadcrumbs.length !== 0) { - return [homeBreadcrumb, ...navBreadcrumbs, ...projectBreadcrumbs.breadcrumbs]; + return [rootCrumb, ...navBreadcrumbs, ...projectBreadcrumbs.breadcrumbs]; } // otherwise try to merge legacy breadcrumbs with navigational project breadcrumbs using deeplinkid @@ -70,12 +75,50 @@ export function buildBreadcrumbs({ } if (chromeBreadcrumbStartIndex === -1) { - return [homeBreadcrumb, ...navBreadcrumbs]; + return [rootCrumb, ...navBreadcrumbs]; } else { return [ - homeBreadcrumb, + rootCrumb, ...navBreadcrumbs.slice(0, navBreadcrumbEndIndex), ...chromeBreadcrumbs.slice(chromeBreadcrumbStartIndex), ]; } } + +function buildRootCrumb({ + projectsUrl, + projectName, + projectUrl, +}: { + projectsUrl?: string; + projectName?: string; + projectUrl?: string; +}): ChromeProjectBreadcrumb { + return { + text: + projectName ?? + i18n.translate('core.ui.primaryNav.cloud.projectLabel', { + defaultMessage: 'Project', + }), + popoverContent: ( + + + , + + + , + ]} + /> + ), + popoverProps: { panelPaddingSize: 'none' }, + }; +} diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/home_breadcrumbs.tsx b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/home_breadcrumbs.tsx deleted file mode 100644 index 62bfad1b7809..000000000000 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/home_breadcrumbs.tsx +++ /dev/null @@ -1,25 +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 { ChromeProjectBreadcrumb } from '@kbn/core-chrome-browser'; -import { EuiIcon } from '@elastic/eui'; -import React from 'react'; -import { i18n } from '@kbn/i18n'; - -export const createHomeBreadcrumb = ({ - homeHref, -}: { - homeHref: string; -}): ChromeProjectBreadcrumb => { - return { - text: , - title: i18n.translate('core.ui.chrome.breadcrumbs.homeLink', { defaultMessage: 'Home' }), - href: homeHref, - 'data-test-subj': 'breadcrumb-home', - }; -}; diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts index 52e27669e551..7e1347f8534c 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts @@ -86,12 +86,35 @@ describe('breadcrumbs', () => { expect(breadcrumbs).toMatchInlineSnapshot(` Array [ Object { - "data-test-subj": "breadcrumb-home", - "href": "/", - "text": + + , + + + , + ] + } + size="s" />, - "title": "Home", + "popoverProps": Object { + "panelPaddingSize": "none", + }, + "text": "Project", }, Object { "deepLinkId": "navItem1", @@ -125,12 +148,35 @@ describe('breadcrumbs', () => { expect(breadcrumbs).toMatchInlineSnapshot(` Array [ Object { - "data-test-subj": "breadcrumb-home", - "href": "/", - "text": + + , + + + , + ] + } + size="s" />, - "title": "Home", + "popoverProps": Object { + "panelPaddingSize": "none", + }, + "text": "Project", }, Object { "href": "/custom1", @@ -158,12 +204,35 @@ describe('breadcrumbs', () => { expect(breadcrumbs).toMatchInlineSnapshot(` Array [ Object { - "data-test-subj": "breadcrumb-home", - "href": "/", - "text": + + , + + + , + ] + } + size="s" />, - "title": "Home", + "popoverProps": Object { + "panelPaddingSize": "none", + }, + "text": "Project", }, Object { "deepLinkId": "navItem1", diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts index 9fb81c0c9a97..38766a026cdc 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts @@ -48,6 +48,7 @@ export class ProjectNavigationService { private projectHome$ = new BehaviorSubject(undefined); private projectsUrl$ = new BehaviorSubject(undefined); private projectName$ = new BehaviorSubject(undefined); + private projectUrl$ = new BehaviorSubject(undefined); private projectNavigation$ = new BehaviorSubject(undefined); private activeNodes$ = new BehaviorSubject([]); private projectNavigationNavTreeFlattened: Record = {}; @@ -106,6 +107,9 @@ export class ProjectNavigationService { getProjectName$: () => { return this.projectName$.asObservable(); }, + setProjectUrl: (projectUrl: string) => { + this.projectUrl$.next(projectUrl); + }, setProjectNavigation: (projectNavigation: ChromeProjectNavigation) => { this.projectNavigation$.next(projectNavigation); this.projectNavigationNavTreeFlattened = flattenNav(projectNavigation.navigationTree); @@ -136,17 +140,30 @@ export class ProjectNavigationService { return combineLatest([ this.projectBreadcrumbs$, this.activeNodes$, - this.projectHome$.pipe(map((homeHref) => homeHref ?? '/')), chromeBreadcrumbs$, + this.projectsUrl$, + this.projectUrl$, + this.projectName$, ]).pipe( - map(([projectBreadcrumbs, activeNodes, homeHref, chromeBreadcrumbs]) => { - return buildBreadcrumbs({ - homeHref: this.http?.basePath.prepend?.(homeHref) ?? homeHref, + map( + ([ projectBreadcrumbs, activeNodes, chromeBreadcrumbs, - }); - }) + projectsUrl, + projectUrl, + projectName, + ]) => { + return buildBreadcrumbs({ + projectUrl, + projectName, + projectsUrl, + projectBreadcrumbs, + activeNodes, + chromeBreadcrumbs, + }); + } + ) ); }, }; diff --git a/packages/core/chrome/core-chrome-browser-internal/src/types.ts b/packages/core/chrome/core-chrome-browser-internal/src/types.ts index 009aa57ee6b3..aefe477dd01f 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/types.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/types.ts @@ -56,6 +56,12 @@ export interface InternalChromeStart extends ChromeStart { */ setProjectName(projectName: string): void; + /** + * Sets the project url. + * @param projectUrl + */ + setProjectUrl(projectUrl: string): void; + /** * Sets the project navigation config to be used for rendering project navigation. * It is used for default project sidenav, project breadcrumbs, tracking active deep link. diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/breadcrumbs.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/breadcrumbs.tsx new file mode 100644 index 000000000000..4ce22ba727e1 --- /dev/null +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/breadcrumbs.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 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 { EuiBreadcrumbs } from '@elastic/eui'; +import classNames from 'classnames'; +import React from 'react'; +import useObservable from 'react-use/lib/useObservable'; +import { Observable } from 'rxjs'; +import type { ChromeBreadcrumb } from '@kbn/core-chrome-browser'; + +interface Props { + breadcrumbs$: Observable; +} + +export function Breadcrumbs({ breadcrumbs$ }: Props) { + const breadcrumbs = useObservable(breadcrumbs$, []); + let crumbs = breadcrumbs; + + if (breadcrumbs.length === 0) { + crumbs = [{ text: 'Kibana' }]; + } + + crumbs = crumbs.map((breadcrumb, i) => { + const isLast = i === breadcrumbs.length - 1; + const { deepLinkId, ...rest } = breadcrumb; + + return { + ...rest, + href: isLast ? undefined : breadcrumb.href, + onClick: isLast ? undefined : breadcrumb.onClick, + 'data-test-subj': classNames( + 'breadcrumb', + deepLinkId && `breadcrumb-deepLinkId-${deepLinkId}`, + breadcrumb['data-test-subj'], + i === 0 && 'first', + isLast && 'last' + ), + }; + }); + + return ; +} diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx index 703d1f0b5de5..04e5773e176b 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx @@ -28,8 +28,6 @@ describe('Header', () => { helpSupportUrl$: Rx.of('app/help'), helpMenuLinks$: Rx.of([]), homeHref$: Rx.of('app/home'), - projectsUrl$: Rx.of('/projects/'), - projectName$: Rx.of('My Project'), kibanaVersion: '8.9', loadingCount$: Rx.of(0), navControlsLeft$: Rx.of([]), @@ -49,16 +47,4 @@ describe('Header', () => { expect(await screen.findByTestId('euiCollapsibleNavButton')).toBeVisible(); expect(await screen.findByText('Hello, world!')).toBeVisible(); }); - - it('displays the link to projects', async () => { - render( - - Hello, world! - - ); - - const projectsLink = screen.getByTestId('projectsLink'); - expect(projectsLink).toHaveAttribute('href', '/projects/'); - expect(projectsLink).toHaveTextContent('My Project'); - }); }); diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx index 7ac11ecb5bc5..0892b0c36391 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx @@ -8,7 +8,6 @@ import { EuiHeader, - EuiHeaderLink, EuiHeaderLogo, EuiHeaderSection, EuiHeaderSectionItem, @@ -36,7 +35,7 @@ import React, { useCallback } from 'react'; import useObservable from 'react-use/lib/useObservable'; import { debounceTime, Observable, of } from 'rxjs'; import { useHeaderActionMenuMounter } from '../header/header_action_menu'; -import { HeaderBreadcrumbs } from '../header/header_breadcrumbs'; +import { Breadcrumbs } from './breadcrumbs'; import { HeaderHelpMenu } from '../header/header_help_menu'; import { HeaderNavControls } from '../header/header_nav_controls'; import { HeaderTopBanner } from '../header/header_top_banner'; @@ -51,6 +50,7 @@ const getHeaderCss = ({ size }: EuiThemeComputed) => ({ min-width: 56px; /* 56 = 40 + 8 + 8 */ padding: 0 ${size.s}; cursor: pointer; + margin-left: -${size.s}; // to get equal spacing between .euiCollapsibleNavButtonWrapper, logo and breadcrumbs `, logo: css` min-width: 0; /* overrides min-width: 40px */ @@ -62,12 +62,6 @@ const getHeaderCss = ({ size }: EuiThemeComputed) => ({ top: 2px; `, }, - projectName: { - link: css` - /* TODO: make header layout more flexible? */ - max-width: 320px; - `, - }, }); type HeaderCss = ReturnType; @@ -78,11 +72,6 @@ const headerStrings = { defaultMessage: 'Go to home page', }), }, - cloud: { - linkToProjects: i18n.translate('core.ui.primaryNav.cloud.linkToProjects', { - defaultMessage: 'Projects', - }), - }, nav: { closeNavAriaLabel: i18n.translate('core.ui.primaryNav.toggleNavAriaLabel', { defaultMessage: 'Toggle primary navigation', @@ -101,8 +90,6 @@ export interface Props { helpSupportUrl$: Observable; helpMenuLinks$: Observable; homeHref$: Observable; - projectsUrl$: Observable; - projectName$: Observable; kibanaVersion: string; application: InternalApplicationStart; loadingCount$: ReturnType; @@ -177,8 +164,6 @@ export const ProjectHeader = ({ ...observables }: Props) => { const headerActionMenuMounter = useHeaderActionMenuMounter(observables.actionMenu$); - const projectsUrl = useObservable(observables.projectsUrl$); - const projectName = useObservable(observables.projectName$); const { euiTheme } = useEuiTheme(); const headerCss = getHeaderCss(euiTheme); const { logo: logoCss } = headerCss; @@ -215,19 +200,9 @@ export const ProjectHeader = ({ - - - {projectName ?? headerStrings.cloud.linkToProjects} - - - - + diff --git a/packages/core/chrome/core-chrome-browser-mocks/src/chrome_service.mock.ts b/packages/core/chrome/core-chrome-browser-mocks/src/chrome_service.mock.ts index 191edc708b64..4f1732d940c3 100644 --- a/packages/core/chrome/core-chrome-browser-mocks/src/chrome_service.mock.ts +++ b/packages/core/chrome/core-chrome-browser-mocks/src/chrome_service.mock.ts @@ -71,6 +71,7 @@ const createStartContractMock = () => { project: { setHome: jest.fn(), setProjectsUrl: jest.fn(), + setProjectUrl: jest.fn(), setProjectName: jest.fn(), setNavigation: jest.fn(), setSideNavComponent: jest.fn(), diff --git a/x-pack/plugins/serverless/public/plugin.tsx b/x-pack/plugins/serverless/public/plugin.tsx index 6333d9a5f58a..8a60db4c0376 100644 --- a/x-pack/plugins/serverless/public/plugin.tsx +++ b/x-pack/plugins/serverless/public/plugin.tsx @@ -69,6 +69,9 @@ export class ServerlessPlugin if (dependencies.cloud.serverless.projectName) { project.setProjectName(dependencies.cloud.serverless.projectName); } + if (dependencies.cloud.deploymentUrl) { + project.setProjectUrl(dependencies.cloud.deploymentUrl); + } return { setSideNavComponent: (sideNavigationComponent) => diff --git a/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts b/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts index 41101d5a653d..5c497b47a6e1 100644 --- a/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts +++ b/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts @@ -153,9 +153,6 @@ export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { async expectExists() { await testSubjects.existOrFail('breadcrumbs'); }, - async clickHome() { - await testSubjects.click('~breadcrumb-home'); - }, async expectBreadcrumbExists(by: { deepLinkId: AppDeepLinkId } | { text: string }) { log.debug( 'ServerlessCommonNavigation.breadcrumbs.expectBreadcrumbExists', diff --git a/x-pack/test_serverless/functional/test_suites/observability/navigation.ts b/x-pack/test_serverless/functional/test_suites/observability/navigation.ts index 4b94df8c51bc..a295d93e009b 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/navigation.ts @@ -76,7 +76,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ deepLinkId: 'management' }); // navigate back to serverless oblt overview - await svlCommonNavigation.breadcrumbs.clickHome(); + await svlCommonNavigation.clickLogo(); await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ deepLinkId: 'observabilityOnboarding', }); diff --git a/x-pack/test_serverless/functional/test_suites/search/navigation.ts b/x-pack/test_serverless/functional/test_suites/search/navigation.ts index 26c2c7cc47ce..b4244a96b82a 100644 --- a/x-pack/test_serverless/functional/test_suites/search/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/search/navigation.ts @@ -61,7 +61,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await testSubjects.existOrFail(`indicesTab`); // navigate back to serverless search overview - await svlCommonNavigation.breadcrumbs.clickHome(); + await svlCommonNavigation.clickLogo(); await svlCommonNavigation.sidenav.expectLinkActive({ deepLinkId: 'serverlessElasticsearch', }); diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts index ef33a898de4f..e3c8de72570b 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts @@ -40,7 +40,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { deepLinkId: 'securitySolutionUI:alerts' as AppDeepLinkId, }); await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Alerts' }); - await svlCommonNavigation.breadcrumbs.clickHome(); + await svlCommonNavigation.clickLogo(); await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Get started' }); }); From ce6cb902788861a1bc50efd878198efafb6a7a3f Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Tue, 31 Oct 2023 11:15:03 -0400 Subject: [PATCH 11/12] fix(slo): remove groupBy on update (#170233) --- .../apm_availability_indicator_type_form.tsx | 2 ++ .../apm_latency/apm_latency_indicator_type_form.tsx | 2 ++ .../slo_edit/components/common/index_field_selector.tsx | 6 ++++-- .../custom_kql/custom_kql_indicator_type_form.tsx | 2 ++ .../components/custom_metric/custom_metric_type_form.tsx | 2 ++ .../components/histogram/histogram_indicator_type_form.tsx | 2 ++ .../timeslice_metric/timeslice_metric_indicator.tsx | 2 ++ 7 files changed, 16 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx index d22509da4359..b58ee9763438 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx @@ -7,6 +7,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import React, { useEffect } from 'react'; import { useFormContext } from 'react-hook-form'; import { useFetchApmIndex } from '../../../../hooks/slo/use_fetch_apm_indices'; @@ -136,6 +137,7 @@ export function ApmAvailabilityIndicatorTypeForm() { {i18n.translate('xpack.observability.slo.sloEdit.groupBy.label', { diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx index af357ea0c18d..32b5729762ab 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx @@ -7,6 +7,7 @@ import { EuiFieldNumber, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiIconTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import React, { useEffect } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; import { useFetchApmIndex } from '../../../../hooks/slo/use_fetch_apm_indices'; @@ -179,6 +180,7 @@ export function ApmLatencyIndicatorTypeForm() { {i18n.translate('xpack.observability.slo.sloEdit.groupBy.label', { diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx index ef9121e871bb..936d39dfa9b9 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx @@ -20,6 +20,7 @@ interface Props { isDisabled: boolean; isLoading: boolean; isRequired?: boolean; + defaultValue?: string; } export function IndexFieldSelector({ indexFields, @@ -29,6 +30,7 @@ export function IndexFieldSelector({ isDisabled, isLoading, isRequired = false, + defaultValue = '', }: Props) { const { control, getFieldState } = useFormContext(); const [options, setOptions] = useState(createOptionsFromFields(indexFields)); @@ -41,7 +43,7 @@ export function IndexFieldSelector({ { diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx index 8555750fd6ff..6c5d4dce730b 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx @@ -7,6 +7,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import React from 'react'; import { useFormContext } from 'react-hook-form'; import { useFetchIndexPatternFields } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; @@ -138,6 +139,7 @@ export function CustomKqlIndicatorTypeForm() { {i18n.translate('xpack.observability.slo.sloEdit.groupBy.label', { diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx index 45870dcd68bd..d69619d1121e 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx @@ -15,6 +15,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import React from 'react'; import { useFormContext } from 'react-hook-form'; import { useFetchIndexPatternFields } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; @@ -153,6 +154,7 @@ export function CustomMetricIndicatorTypeForm() { {i18n.translate('xpack.observability.slo.sloEdit.groupBy.label', { diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx index eb18e0a36362..50a84c121d73 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx @@ -15,6 +15,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import React from 'react'; import { useFormContext } from 'react-hook-form'; import { useFetchIndexPatternFields } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; @@ -140,6 +141,7 @@ export function HistogramIndicatorTypeForm() { {i18n.translate('xpack.observability.slo.sloEdit.groupBy.label', { diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/timeslice_metric_indicator.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/timeslice_metric_indicator.tsx index 5d455a601e3d..b2d788bf2865 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/timeslice_metric_indicator.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/timeslice_metric_indicator.tsx @@ -18,6 +18,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import React from 'react'; import { useFormContext } from 'react-hook-form'; +import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import { useFetchIndexPatternFields } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; import { CreateSLOForm } from '../../types'; import { DataPreviewChart } from '../common/data_preview_chart'; @@ -130,6 +131,7 @@ export function TimesliceMetricIndicatorTypeForm() { {i18n.translate('xpack.observability.slo.sloEdit.groupBy.label', { From 7ad80a0884801e40ca8fb2209ff6f5388084895d Mon Sep 17 00:00:00 2001 From: Jeramy Soucy Date: Tue, 31 Oct 2023 11:30:13 -0400 Subject: [PATCH 12/12] =?UTF-8?q?Upgrades=20browserify-sign@4.0.4=E2=86=92?= =?UTF-8?q?4.2.2=20(#170137)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Upgrades browserify-sign from v4.0.4 to v4.2.2 --- yarn.lock | 85 +++++++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/yarn.lock b/yarn.lock index 2d38221a2d11..d6bbe1679241 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11241,16 +11241,7 @@ asap@^2.0.0, asap@~2.0.3: resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= -asn1.js@^4.0.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" - integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -asn1.js@^5.0.0: +asn1.js@^5.0.0, asn1.js@^5.2.0: version "5.4.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== @@ -11924,11 +11915,16 @@ blurhash@^2.0.1: resolved "https://registry.yarnpkg.com/blurhash/-/blurhash-2.0.1.tgz#7f134ad0cf3cbb6bcceb81ea51b82e1423009dca" integrity sha512-qAJW99ZIEVJqLKvR6EUtMavaalYiFgfHNvwO6eiqHE7RTBZYGQLPJvzs4WlnqSQPxZgqSPH/n4kRJIHzb/Y7dg== -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.11.9: +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: version "4.11.9" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw== +bn.js@^5.0.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + body-parser@1.19.2: version "1.19.2" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e" @@ -12117,26 +12113,28 @@ browserify-optional@^1.0.1: ast-types "^0.7.0" browser-resolve "^1.8.1" -browserify-rsa@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" - integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= +browserify-rsa@^4.0.0, browserify-rsa@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== dependencies: - bn.js "^4.1.0" + bn.js "^5.0.0" randombytes "^2.0.1" browserify-sign@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" - integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= - dependencies: - bn.js "^4.1.1" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.2" - elliptic "^6.0.0" - inherits "^2.0.1" - parse-asn1 "^5.0.0" + version "4.2.2" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.2.tgz#e78d4b69816d6e3dd1c747e64e9947f9ad79bc7e" + integrity sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg== + dependencies: + bn.js "^5.2.1" + browserify-rsa "^4.1.0" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.4" + inherits "^2.0.4" + parse-asn1 "^5.1.6" + readable-stream "^3.6.2" + safe-buffer "^5.2.1" browserify-zlib@^0.2.0: version "0.2.0" @@ -13498,20 +13496,21 @@ create-ecdh@^4.0.0: bn.js "^4.1.0" elliptic "^6.0.0" -create-hash@^1.1.0, create-hash@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" - integrity sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0= +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== dependencies: cipher-base "^1.0.1" inherits "^2.0.1" - ripemd160 "^2.0.0" + md5.js "^1.3.4" + ripemd160 "^2.0.1" sha.js "^2.4.0" -create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: - version "1.1.6" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06" - integrity sha1-rLniIaThe9sHbpBlfEK5PjcmzwY= +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== dependencies: cipher-base "^1.0.3" create-hash "^1.1.0" @@ -15225,7 +15224,7 @@ element-resize-detector@^1.2.2: dependencies: batch-processor "1.0.0" -elliptic@^6.0.0: +elliptic@^6.0.0, elliptic@^6.5.4: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== @@ -23653,16 +23652,16 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-asn1@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" - integrity sha1-N8T5t+06tlx0gXtfJICTf7+XxxI= +parse-asn1@^5.0.0, parse-asn1@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== dependencies: - asn1.js "^4.0.0" + asn1.js "^5.2.0" browserify-aes "^1.0.0" - create-hash "^1.1.0" evp_bytestokey "^1.0.0" pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" parse-entities@^2.0.0: version "2.0.0"