From d0e30f5475f5c2628c06e4b21353470c5d79704c Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 10 Nov 2021 15:47:00 +0100 Subject: [PATCH 01/51] [Security Solution][Investigations] Fix overlapping tooltips (#117874) * feat: allow to pass `tooltipPosition` to `DefaultDraggable` * fix: prevent suricata field name and google url tooltips from overlapping * test: add test for passing the tooltipPosition * chore: distinguish between type imports and regular imports * test: update suricata signature snapshots * test: make sure that suricata signature tooltips do not overlap Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../cypress/helpers/rules.ts | 15 +++++++++++++ .../timelines/row_renderers.spec.ts | 22 +++++++++++++++++++ .../cypress/screens/timeline.ts | 6 +++++ .../components/draggables/index.test.tsx | 17 ++++++++++++++ .../common/components/draggables/index.tsx | 19 ++++++++++++---- .../suricata_signature.test.tsx.snap | 1 + .../renderers/suricata/suricata_signature.tsx | 1 + 7 files changed, 77 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/security_solution/cypress/helpers/rules.ts b/x-pack/plugins/security_solution/cypress/helpers/rules.ts index ebe357c382770..63542f9a78f84 100644 --- a/x-pack/plugins/security_solution/cypress/helpers/rules.ts +++ b/x-pack/plugins/security_solution/cypress/helpers/rules.ts @@ -20,3 +20,18 @@ export const formatMitreAttackDescription = (mitre: Mitre[]) => { ) .join(''); }; + +export const elementsOverlap = ($element1: JQuery, $element2: JQuery) => { + const rectA = $element1[0].getBoundingClientRect(); + const rectB = $element2[0].getBoundingClientRect(); + + // If they don't overlap horizontally, they don't overlap + if (rectA.right < rectB.left || rectB.right < rectA.left) { + return false; + } else if (rectA.bottom < rectB.top || rectB.bottom < rectA.top) { + // If they don't overlap vertically, they don't overlap + return false; + } else { + return true; + } +}; diff --git a/x-pack/plugins/security_solution/cypress/integration/timelines/row_renderers.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timelines/row_renderers.spec.ts index 0755142fbdc58..2219339d0577d 100644 --- a/x-pack/plugins/security_solution/cypress/integration/timelines/row_renderers.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/timelines/row_renderers.spec.ts @@ -5,12 +5,16 @@ * 2.0. */ +import { elementsOverlap } from '../../helpers/rules'; import { TIMELINE_ROW_RENDERERS_DISABLE_ALL_BTN, TIMELINE_ROW_RENDERERS_MODAL_CLOSE_BUTTON, TIMELINE_ROW_RENDERERS_MODAL_ITEMS_CHECKBOX, TIMELINE_ROW_RENDERERS_SEARCHBOX, TIMELINE_SHOW_ROW_RENDERERS_GEAR, + TIMELINE_ROW_RENDERERS_SURICATA_SIGNATURE, + TIMELINE_ROW_RENDERERS_SURICATA_SIGNATURE_TOOLTIP, + TIMELINE_ROW_RENDERERS_SURICATA_LINK_TOOLTIP, } from '../../screens/timeline'; import { cleanKibana } from '../../tasks/common'; @@ -81,4 +85,22 @@ describe('Row renderers', () => { cy.wait('@updateTimeline').its('response.statusCode').should('eq', 200); }); + + describe('Suricata', () => { + it('Signature tooltips do not overlap', () => { + // Hover the signature to show the tooltips + cy.get(TIMELINE_ROW_RENDERERS_SURICATA_SIGNATURE) + .parents('.euiPopover__anchor') + .trigger('mouseover'); + + cy.get(TIMELINE_ROW_RENDERERS_SURICATA_LINK_TOOLTIP).then(($googleLinkTooltip) => { + cy.get(TIMELINE_ROW_RENDERERS_SURICATA_SIGNATURE_TOOLTIP).then(($signatureTooltip) => { + expect( + elementsOverlap($googleLinkTooltip, $signatureTooltip), + 'tooltips do not overlap' + ).to.equal(false); + }); + }); + }); + }); }); diff --git a/x-pack/plugins/security_solution/cypress/screens/timeline.ts b/x-pack/plugins/security_solution/cypress/screens/timeline.ts index f7495f3730dc4..619e7d01f10e2 100644 --- a/x-pack/plugins/security_solution/cypress/screens/timeline.ts +++ b/x-pack/plugins/security_solution/cypress/screens/timeline.ts @@ -245,6 +245,12 @@ export const TIMELINE_ROW_RENDERERS_MODAL_ITEMS_CHECKBOX = `${TIMELINE_ROW_RENDE export const TIMELINE_ROW_RENDERERS_SEARCHBOX = `${TIMELINE_ROW_RENDERERS_MODAL} input[type="search"]`; +export const TIMELINE_ROW_RENDERERS_SURICATA_SIGNATURE = `${TIMELINE_ROW_RENDERERS_MODAL} [data-test-subj="render-content-suricata.eve.alert.signature"]`; + +export const TIMELINE_ROW_RENDERERS_SURICATA_LINK_TOOLTIP = `[data-test-subj="externalLinkTooltip"]`; + +export const TIMELINE_ROW_RENDERERS_SURICATA_SIGNATURE_TOOLTIP = `[data-test-subj="suricata.eve.alert.signature-tooltip"]`; + export const TIMELINE_SHOW_ROW_RENDERERS_GEAR = '[data-test-subj="show-row-renderers-gear"]'; export const TIMELINE_TABS = '[data-test-subj="timeline"] .euiTabs'; diff --git a/x-pack/plugins/security_solution/public/common/components/draggables/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/draggables/index.test.tsx index f77bf0f347f79..e1f052dbf83b0 100644 --- a/x-pack/plugins/security_solution/public/common/components/draggables/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/draggables/index.test.tsx @@ -7,6 +7,7 @@ import { shallow } from 'enzyme'; import React from 'react'; +import { EuiToolTip } from '@elastic/eui'; import { DRAGGABLE_KEYBOARD_INSTRUCTIONS_NOT_DRAGGING_SCREEN_READER_ONLY } from '../drag_and_drop/translations'; import { TestProviders } from '../../mock'; @@ -326,5 +327,21 @@ describe('draggables', () => { expect(wrapper.find('[data-test-subj="some-field-tooltip"]').first().exists()).toBe(false); }); + + test('it uses the specified tooltipPosition', () => { + const wrapper = mount( + + + + ); + + expect(wrapper.find(EuiToolTip).first().props().position).toEqual('top'); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/draggables/index.tsx b/x-pack/plugins/security_solution/public/common/components/draggables/index.tsx index e33a8e42e6a39..26eaec4f7a76e 100644 --- a/x-pack/plugins/security_solution/public/common/components/draggables/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/draggables/index.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import { EuiBadge, EuiToolTip, IconType } from '@elastic/eui'; +import { EuiBadge, EuiToolTip } from '@elastic/eui'; +import type { IconType, ToolTipPositions } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; @@ -29,6 +30,7 @@ export interface DefaultDraggableType { children?: React.ReactNode; timelineId?: string; tooltipContent?: React.ReactNode; + tooltipPosition?: ToolTipPositions; } /** @@ -60,11 +62,13 @@ export const Content = React.memo<{ children?: React.ReactNode; field: string; tooltipContent?: React.ReactNode; + tooltipPosition?: ToolTipPositions; value?: string | null; -}>(({ children, field, tooltipContent, value }) => +}>(({ children, field, tooltipContent, tooltipPosition, value }) => !tooltipContentIsExplicitlyNull(tooltipContent) ? ( <>{children ? children : value} @@ -88,6 +92,7 @@ Content.displayName = 'Content'; * @param children - defaults to displaying `value`, this allows an arbitrary visualization to be displayed in lieu of the default behavior * @param tooltipContent - defaults to displaying `field`, pass `null` to * prevent a tooltip from being displayed, or pass arbitrary content + * @param tooltipPosition - defaults to eui's default tooltip position * @param queryValue - defaults to `value`, this query overrides the `queryMatch.value` used by the `DataProvider` that represents the data * @param hideTopN - defaults to `false`, when true, the option to aggregate this field will be hidden */ @@ -102,6 +107,7 @@ export const DefaultDraggable = React.memo( children, timelineId, tooltipContent, + tooltipPosition, queryValue, }) => { const dataProviderProp: DataProvider = useMemo( @@ -128,11 +134,16 @@ export const DefaultDraggable = React.memo( ) : ( - + {children} ), - [children, field, tooltipContent, value] + [children, field, tooltipContent, tooltipPosition, value] ); if (value == null) return null; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/__snapshots__/suricata_signature.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/__snapshots__/suricata_signature.test.tsx.snap index e55465cfd8895..c9f04ca2313a3 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/__snapshots__/suricata_signature.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/__snapshots__/suricata_signature.test.tsx.snap @@ -26,6 +26,7 @@ exports[`SuricataSignature rendering it renders the default SuricataSignature 1` data-test-subj="draggable-signature-link" field="suricata.eve.alert.signature" id="suricata-signature-default-draggable-test-doc-id-123-suricata.eve.alert.signature" + tooltipPosition="bottom" value="ET SCAN ATTACK Hello" >
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_signature.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_signature.tsx index 18e2d0844779b..ea721200730e9 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_signature.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_signature.tsx @@ -130,6 +130,7 @@ export const SuricataSignature = React.memo<{ id={`suricata-signature-default-draggable-${contextId}-${id}-${SURICATA_SIGNATURE_FIELD_NAME}`} isDraggable={isDraggable} value={signature} + tooltipPosition="bottom" >
From 9888b7fec3f84e76d8f32eb1757a71fa731c867d Mon Sep 17 00:00:00 2001 From: Brian Seeders Date: Wed, 10 Nov 2021 10:33:20 -0500 Subject: [PATCH 02/51] [CI] Rebalance/split cigroups and speed up overall CI time (#113676) --- .buildkite/pipelines/es_snapshots/verify.yml | 6 ++--- .buildkite/pipelines/flaky_tests/runner.js | 6 ++--- .buildkite/pipelines/hourly.yml | 12 +++++----- .buildkite/pipelines/pull_request/base.yml | 16 ++++++------- .../type_check_plugin_public_api_docs.sh | 24 ++++++++++++++++--- .ci/ci_groups.yml | 14 +++++++++++ test/functional/apps/management/index.ts | 2 +- test/functional/apps/visualize/index.ts | 4 ++-- .../security_and_spaces/tests/index.ts | 2 +- x-pack/test/api_integration/apis/index.ts | 4 ++-- .../api_integration/apis/security/index.ts | 2 +- .../test/api_integration/apis/spaces/index.ts | 2 +- .../security_and_spaces/tests/basic/index.ts | 2 +- .../security_and_spaces/tests/trial/index.ts | 3 +-- .../exception_operators_data_types/index.ts | 4 ++-- .../test/functional/apps/dashboard/index.ts | 2 +- x-pack/test/functional/apps/discover/index.ts | 2 +- x-pack/test/functional/apps/lens/index.ts | 13 ++++++---- x-pack/test/functional/apps/maps/index.js | 8 +++++-- x-pack/test/functional/apps/ml/index.ts | 21 +++++++++------- x-pack/test/functional/apps/security/index.ts | 2 +- .../test/functional/apps/transform/index.ts | 2 +- x-pack/test/functional_basic/apps/ml/index.ts | 2 +- .../security_and_spaces/apis/index.ts | 2 +- .../functional/tests/index.ts | 2 +- .../tests/kerberos/index.ts | 2 +- .../tests/saml/index.ts | 2 +- .../tests/session_idle/index.ts | 2 +- 28 files changed, 105 insertions(+), 60 deletions(-) diff --git a/.buildkite/pipelines/es_snapshots/verify.yml b/.buildkite/pipelines/es_snapshots/verify.yml index 9cddade0b7482..93f8765ec16f7 100755 --- a/.buildkite/pipelines/es_snapshots/verify.yml +++ b/.buildkite/pipelines/es_snapshots/verify.yml @@ -29,7 +29,7 @@ steps: label: 'Default CI Group' parallelism: 13 agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 150 key: default-cigroup @@ -41,7 +41,7 @@ steps: - command: CI_GROUP=Docker .buildkite/scripts/steps/functional/xpack_cigroup.sh label: 'Docker CI Group' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 key: default-cigroup-docker @@ -77,7 +77,7 @@ steps: - command: .buildkite/scripts/steps/test/api_integration.sh label: 'API Integration Tests' agents: - queue: jest + queue: n2-2 timeout_in_minutes: 120 key: api-integration diff --git a/.buildkite/pipelines/flaky_tests/runner.js b/.buildkite/pipelines/flaky_tests/runner.js index b5ccab137fd01..0c2db5c724f7b 100644 --- a/.buildkite/pipelines/flaky_tests/runner.js +++ b/.buildkite/pipelines/flaky_tests/runner.js @@ -78,7 +78,7 @@ for (const testSuite of testSuites) { steps.push({ command: `CI_GROUP=${CI_GROUP} .buildkite/scripts/steps/functional/xpack_cigroup.sh`, label: `Default CI Group ${CI_GROUP}`, - agents: { queue: 'ci-group-6' }, + agents: { queue: 'n2-4' }, depends_on: 'build', parallelism: RUN_COUNT, concurrency: concurrency, @@ -103,7 +103,7 @@ for (const testSuite of testSuites) { steps.push({ command: `.buildkite/scripts/steps/functional/${IS_XPACK ? 'xpack' : 'oss'}_firefox.sh`, label: `${IS_XPACK ? 'Default' : 'OSS'} Firefox`, - agents: { queue: IS_XPACK ? 'ci-group-6' : 'ci-group-4d' }, + agents: { queue: IS_XPACK ? 'n2-4' : 'ci-group-4d' }, depends_on: 'build', parallelism: RUN_COUNT, concurrency: concurrency, @@ -118,7 +118,7 @@ for (const testSuite of testSuites) { IS_XPACK ? 'xpack' : 'oss' }_accessibility.sh`, label: `${IS_XPACK ? 'Default' : 'OSS'} Accessibility`, - agents: { queue: IS_XPACK ? 'ci-group-6' : 'ci-group-4d' }, + agents: { queue: IS_XPACK ? 'n2-4' : 'ci-group-4d' }, depends_on: 'build', parallelism: RUN_COUNT, concurrency: concurrency, diff --git a/.buildkite/pipelines/hourly.yml b/.buildkite/pipelines/hourly.yml index 9e9990816ad1d..534300cce3988 100644 --- a/.buildkite/pipelines/hourly.yml +++ b/.buildkite/pipelines/hourly.yml @@ -19,7 +19,7 @@ steps: label: 'Default CI Group' parallelism: 13 agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 250 key: default-cigroup @@ -31,7 +31,7 @@ steps: - command: CI_GROUP=Docker .buildkite/scripts/steps/functional/xpack_cigroup.sh label: 'Docker CI Group' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 key: default-cigroup-docker @@ -67,7 +67,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_accessibility.sh label: 'Default Accessibility Tests' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: @@ -89,7 +89,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_firefox.sh label: 'Default Firefox Tests' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: @@ -100,7 +100,7 @@ steps: - command: .buildkite/scripts/steps/functional/oss_misc.sh label: 'OSS Misc Functional Tests' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: @@ -111,7 +111,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_saved_object_field_metrics.sh label: 'Saved Object Field Metrics' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: diff --git a/.buildkite/pipelines/pull_request/base.yml b/.buildkite/pipelines/pull_request/base.yml index 34db52772e619..b99473c23d746 100644 --- a/.buildkite/pipelines/pull_request/base.yml +++ b/.buildkite/pipelines/pull_request/base.yml @@ -15,9 +15,9 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_cigroup.sh label: 'Default CI Group' - parallelism: 13 + parallelism: 27 agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 150 key: default-cigroup @@ -29,7 +29,7 @@ steps: - command: CI_GROUP=Docker .buildkite/scripts/steps/functional/xpack_cigroup.sh label: 'Docker CI Group' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 key: default-cigroup-docker @@ -65,7 +65,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_accessibility.sh label: 'Default Accessibility Tests' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: @@ -87,7 +87,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_firefox.sh label: 'Default Firefox Tests' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: @@ -98,7 +98,7 @@ steps: - command: .buildkite/scripts/steps/functional/oss_misc.sh label: 'OSS Misc Functional Tests' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: @@ -109,7 +109,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_saved_object_field_metrics.sh label: 'Saved Object Field Metrics' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: @@ -156,7 +156,7 @@ steps: - command: .buildkite/scripts/steps/checks.sh label: 'Checks' agents: - queue: c2-4 + queue: c2-8 key: checks timeout_in_minutes: 120 diff --git a/.buildkite/scripts/steps/checks/type_check_plugin_public_api_docs.sh b/.buildkite/scripts/steps/checks/type_check_plugin_public_api_docs.sh index 1d73d1748ddf7..5827fd5eb2284 100755 --- a/.buildkite/scripts/steps/checks/type_check_plugin_public_api_docs.sh +++ b/.buildkite/scripts/steps/checks/type_check_plugin_public_api_docs.sh @@ -11,9 +11,27 @@ checks-reporter-with-killswitch "Build TS Refs" \ --no-cache \ --force -echo --- Check Types checks-reporter-with-killswitch "Check Types" \ - node scripts/type_check + node scripts/type_check &> target/check_types.log & +check_types_pid=$! + +node --max-old-space-size=12000 scripts/build_api_docs &> target/build_api_docs.log & +api_docs_pid=$! + +wait $check_types_pid +check_types_exit=$? + +wait $api_docs_pid +api_docs_exit=$? + +echo --- Check Types +cat target/check_types.log +if [[ "$check_types_exit" != "0" ]]; then echo "^^^ +++"; fi echo --- Building api docs -node --max-old-space-size=12000 scripts/build_api_docs +cat target/build_api_docs.log +if [[ "$api_docs_exit" != "0" ]]; then echo "^^^ +++"; fi + +if [[ "${api_docs_exit}${check_types_exit}" != "00" ]]; then + exit 1 +fi diff --git a/.ci/ci_groups.yml b/.ci/ci_groups.yml index 9c3a039f51166..1be6e8c196a2d 100644 --- a/.ci/ci_groups.yml +++ b/.ci/ci_groups.yml @@ -25,4 +25,18 @@ xpack: - ciGroup11 - ciGroup12 - ciGroup13 + - ciGroup14 + - ciGroup15 + - ciGroup16 + - ciGroup17 + - ciGroup18 + - ciGroup19 + - ciGroup20 + - ciGroup21 + - ciGroup22 + - ciGroup23 + - ciGroup24 + - ciGroup25 + - ciGroup26 + - ciGroup27 - ciGroupDocker diff --git a/test/functional/apps/management/index.ts b/test/functional/apps/management/index.ts index 4787d7b9ee532..c906697021ecf 100644 --- a/test/functional/apps/management/index.ts +++ b/test/functional/apps/management/index.ts @@ -22,7 +22,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { }); describe('', function () { - this.tags('ciGroup7'); + this.tags('ciGroup9'); loadTestFile(require.resolve('./_create_index_pattern_wizard')); loadTestFile(require.resolve('./_index_pattern_create_delete')); diff --git a/test/functional/apps/visualize/index.ts b/test/functional/apps/visualize/index.ts index 3bc4da0163909..68b95f3521a24 100644 --- a/test/functional/apps/visualize/index.ts +++ b/test/functional/apps/visualize/index.ts @@ -74,8 +74,8 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_metric_chart')); }); - describe('visualize ciGroup4', function () { - this.tags('ciGroup4'); + describe('visualize ciGroup1', function () { + this.tags('ciGroup1'); loadTestFile(require.resolve('./_pie_chart')); loadTestFile(require.resolve('./_shared_item')); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts index a1f15c0db75fd..211fe9ec26863 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts @@ -58,7 +58,7 @@ export async function tearDown(getService: FtrProviderContext['getService']) { // eslint-disable-next-line import/no-default-export export default function alertingApiIntegrationTests({ loadTestFile }: FtrProviderContext) { describe('alerting api integration security and spaces enabled', function () { - this.tags('ciGroup5'); + this.tags('ciGroup17'); loadTestFile(require.resolve('./actions')); loadTestFile(require.resolve('./alerting')); diff --git a/x-pack/test/api_integration/apis/index.ts b/x-pack/test/api_integration/apis/index.ts index c3d08ba306692..56b2042dc4854 100644 --- a/x-pack/test/api_integration/apis/index.ts +++ b/x-pack/test/api_integration/apis/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('apis', function () { - this.tags('ciGroup6'); + this.tags('ciGroup18'); loadTestFile(require.resolve('./search')); loadTestFile(require.resolve('./es')); @@ -27,12 +27,12 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./maps')); loadTestFile(require.resolve('./security_solution')); loadTestFile(require.resolve('./lens')); - loadTestFile(require.resolve('./ml')); loadTestFile(require.resolve('./transform')); loadTestFile(require.resolve('./lists')); loadTestFile(require.resolve('./upgrade_assistant')); loadTestFile(require.resolve('./searchprofiler')); loadTestFile(require.resolve('./painless_lab')); loadTestFile(require.resolve('./file_upload')); + loadTestFile(require.resolve('./ml')); }); } diff --git a/x-pack/test/api_integration/apis/security/index.ts b/x-pack/test/api_integration/apis/security/index.ts index e190e02d9bdea..eb81d8245dbff 100644 --- a/x-pack/test/api_integration/apis/security/index.ts +++ b/x-pack/test/api_integration/apis/security/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security', function () { - this.tags('ciGroup6'); + this.tags('ciGroup18'); // Updates here should be mirrored in `./security_basic.ts` if tests // should also run under a basic license. diff --git a/x-pack/test/api_integration/apis/spaces/index.ts b/x-pack/test/api_integration/apis/spaces/index.ts index 7267329249b22..3ca0040e39ec9 100644 --- a/x-pack/test/api_integration/apis/spaces/index.ts +++ b/x-pack/test/api_integration/apis/spaces/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('spaces', function () { - this.tags('ciGroup6'); + this.tags('ciGroup18'); loadTestFile(require.resolve('./get_active_space')); loadTestFile(require.resolve('./saved_objects')); diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts index 3fb7d7a29af39..ce2f59a115e69 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts @@ -12,7 +12,7 @@ import { createSpacesAndUsers, deleteSpacesAndUsers } from '../../../common/lib/ export default ({ loadTestFile, getService }: FtrProviderContext): void => { describe('cases security and spaces enabled: basic', function () { // Fastest ciGroup for the moment. - this.tags('ciGroup13'); + this.tags('ciGroup27'); before(async () => { await createSpacesAndUsers(getService); diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts index cd4b062c065a0..1605003bf7015 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts @@ -11,8 +11,7 @@ import { createSpacesAndUsers, deleteSpacesAndUsers } from '../../../common/lib/ // eslint-disable-next-line import/no-default-export export default ({ loadTestFile, getService }: FtrProviderContext): void => { describe('cases security and spaces enabled: trial', function () { - // Fastest ciGroup for the moment. - this.tags('ciGroup13'); + this.tags('ciGroup25'); before(async () => { await createSpacesAndUsers(getService); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts index cebd20b698c26..85cc484146032 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../../common/ftr_provider_context'; export default ({ loadTestFile }: FtrProviderContext): void => { describe('Detection exceptions data types and operators', function () { describe('', function () { - this.tags('ciGroup11'); + this.tags('ciGroup23'); loadTestFile(require.resolve('./date')); loadTestFile(require.resolve('./double')); @@ -20,7 +20,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => { }); describe('', function () { - this.tags('ciGroup12'); + this.tags('ciGroup24'); loadTestFile(require.resolve('./ip')); loadTestFile(require.resolve('./ip_array')); diff --git a/x-pack/test/functional/apps/dashboard/index.ts b/x-pack/test/functional/apps/dashboard/index.ts index 73c9b83de917f..59211ecf37f2d 100644 --- a/x-pack/test/functional/apps/dashboard/index.ts +++ b/x-pack/test/functional/apps/dashboard/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('dashboard', function () { - this.tags('ciGroup7'); + this.tags('ciGroup19'); loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./preserve_url')); diff --git a/x-pack/test/functional/apps/discover/index.ts b/x-pack/test/functional/apps/discover/index.ts index af117a2182034..9eda11bc6e6fb 100644 --- a/x-pack/test/functional/apps/discover/index.ts +++ b/x-pack/test/functional/apps/discover/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('discover', function () { - this.tags('ciGroup1'); + this.tags('ciGroup25'); loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./preserve_url')); diff --git a/x-pack/test/functional/apps/lens/index.ts b/x-pack/test/functional/apps/lens/index.ts index f9e4835f044af..79f9b8f645c1a 100644 --- a/x-pack/test/functional/apps/lens/index.ts +++ b/x-pack/test/functional/apps/lens/index.ts @@ -50,10 +50,6 @@ export default function ({ getService, loadTestFile, getPageObjects }: FtrProvid describe('', function () { this.tags(['ciGroup4', 'skipFirefox']); - loadTestFile(require.resolve('./add_to_dashboard')); - loadTestFile(require.resolve('./table')); - loadTestFile(require.resolve('./runtime_fields')); - loadTestFile(require.resolve('./dashboard')); loadTestFile(require.resolve('./colors')); loadTestFile(require.resolve('./chart_data')); loadTestFile(require.resolve('./time_shift')); @@ -69,5 +65,14 @@ export default function ({ getService, loadTestFile, getPageObjects }: FtrProvid // has to be last one in the suite because it overrides saved objects loadTestFile(require.resolve('./rollup')); }); + + describe('', function () { + this.tags(['ciGroup16', 'skipFirefox']); + + loadTestFile(require.resolve('./add_to_dashboard')); + loadTestFile(require.resolve('./table')); + loadTestFile(require.resolve('./runtime_fields')); + loadTestFile(require.resolve('./dashboard')); + }); }); } diff --git a/x-pack/test/functional/apps/maps/index.js b/x-pack/test/functional/apps/maps/index.js index 6a2a843682f26..b85859bf2d5d3 100644 --- a/x-pack/test/functional/apps/maps/index.js +++ b/x-pack/test/functional/apps/maps/index.js @@ -73,8 +73,13 @@ export default function ({ loadTestFile, getService }) { }); describe('', function () { - this.tags('ciGroup10'); + this.tags('ciGroup22'); loadTestFile(require.resolve('./es_geo_grid_source')); + loadTestFile(require.resolve('./embeddable')); + }); + + describe('', function () { + this.tags('ciGroup10'); loadTestFile(require.resolve('./es_pew_pew_source')); loadTestFile(require.resolve('./joins')); loadTestFile(require.resolve('./mapbox_styles')); @@ -83,7 +88,6 @@ export default function ({ loadTestFile, getService }) { loadTestFile(require.resolve('./add_layer_panel')); loadTestFile(require.resolve('./import_geojson')); loadTestFile(require.resolve('./layer_errors')); - loadTestFile(require.resolve('./embeddable')); loadTestFile(require.resolve('./visualize_create_menu')); loadTestFile(require.resolve('./discover')); }); diff --git a/x-pack/test/functional/apps/ml/index.ts b/x-pack/test/functional/apps/ml/index.ts index 2e3a29d50dd11..493813daa4f72 100644 --- a/x-pack/test/functional/apps/ml/index.ts +++ b/x-pack/test/functional/apps/ml/index.ts @@ -13,8 +13,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { describe('machine learning', function () { describe('', function () { - this.tags('ciGroup3'); - before(async () => { await ml.securityCommon.createMlRoles(); await ml.securityCommon.createMlUsers(); @@ -47,12 +45,19 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await ml.testResources.resetKibanaTimeZone(); }); - loadTestFile(require.resolve('./permissions')); - loadTestFile(require.resolve('./pages')); - loadTestFile(require.resolve('./anomaly_detection')); - loadTestFile(require.resolve('./data_visualizer')); - loadTestFile(require.resolve('./data_frame_analytics')); - loadTestFile(require.resolve('./model_management')); + describe('', function () { + this.tags('ciGroup15'); + loadTestFile(require.resolve('./permissions')); + loadTestFile(require.resolve('./pages')); + loadTestFile(require.resolve('./data_visualizer')); + loadTestFile(require.resolve('./data_frame_analytics')); + loadTestFile(require.resolve('./model_management')); + }); + + describe('', function () { + this.tags('ciGroup26'); + loadTestFile(require.resolve('./anomaly_detection')); + }); }); describe('', function () { diff --git a/x-pack/test/functional/apps/security/index.ts b/x-pack/test/functional/apps/security/index.ts index 3b4c6989d38fa..fc9caafbabb29 100644 --- a/x-pack/test/functional/apps/security/index.ts +++ b/x-pack/test/functional/apps/security/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security app', function () { - this.tags('ciGroup4'); + this.tags('ciGroup7'); loadTestFile(require.resolve('./security')); loadTestFile(require.resolve('./doc_level_security_roles')); diff --git a/x-pack/test/functional/apps/transform/index.ts b/x-pack/test/functional/apps/transform/index.ts index 90bb95fd6b3e8..4a9aafb072852 100644 --- a/x-pack/test/functional/apps/transform/index.ts +++ b/x-pack/test/functional/apps/transform/index.ts @@ -16,7 +16,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { const transform = getService('transform'); describe('transform', function () { - this.tags(['ciGroup9', 'transform']); + this.tags(['ciGroup21', 'transform']); before(async () => { await transform.securityCommon.createTransformRoles(); diff --git a/x-pack/test/functional_basic/apps/ml/index.ts b/x-pack/test/functional_basic/apps/ml/index.ts index ed1ab4f417584..af2fdc8c45f29 100644 --- a/x-pack/test/functional_basic/apps/ml/index.ts +++ b/x-pack/test/functional_basic/apps/ml/index.ts @@ -12,7 +12,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { const ml = getService('ml'); describe('machine learning basic license', function () { - this.tags(['ciGroup2', 'skipFirefox', 'mlqa']); + this.tags(['ciGroup14', 'skipFirefox', 'mlqa']); before(async () => { await ml.securityCommon.createMlRoles(); diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts index 5412f9d9bdfed..740b9d91927bf 100644 --- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts +++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts @@ -13,7 +13,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { const supertest = getService('supertest'); describe('saved objects security and spaces enabled', function () { - this.tags('ciGroup8'); + this.tags('ciGroup20'); before(async () => { await createUsersAndRoles(es, supertest); diff --git a/x-pack/test/saved_object_tagging/functional/tests/index.ts b/x-pack/test/saved_object_tagging/functional/tests/index.ts index 7a82574f34b6e..fbf0954382dd1 100644 --- a/x-pack/test/saved_object_tagging/functional/tests/index.ts +++ b/x-pack/test/saved_object_tagging/functional/tests/index.ts @@ -11,7 +11,7 @@ import { createUsersAndRoles } from '../../common/lib'; // eslint-disable-next-line import/no-default-export export default function ({ loadTestFile, getService }: FtrProviderContext) { describe('saved objects tagging - functional tests', function () { - this.tags('ciGroup2'); + this.tags('ciGroup14'); before(async () => { await createUsersAndRoles(getService); diff --git a/x-pack/test/security_api_integration/tests/kerberos/index.ts b/x-pack/test/security_api_integration/tests/kerberos/index.ts index 3faec0badd89e..39aac8cc4ca2f 100644 --- a/x-pack/test/security_api_integration/tests/kerberos/index.ts +++ b/x-pack/test/security_api_integration/tests/kerberos/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security APIs - Kerberos', function () { - this.tags('ciGroup6'); + this.tags('ciGroup16'); loadTestFile(require.resolve('./kerberos_login')); }); diff --git a/x-pack/test/security_api_integration/tests/saml/index.ts b/x-pack/test/security_api_integration/tests/saml/index.ts index 375864c71432d..dbabb835ee980 100644 --- a/x-pack/test/security_api_integration/tests/saml/index.ts +++ b/x-pack/test/security_api_integration/tests/saml/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security APIs - SAML', function () { - this.tags('ciGroup6'); + this.tags('ciGroup18'); loadTestFile(require.resolve('./saml_login')); }); diff --git a/x-pack/test/security_api_integration/tests/session_idle/index.ts b/x-pack/test/security_api_integration/tests/session_idle/index.ts index bbf811de70db4..76457ee7ad0c7 100644 --- a/x-pack/test/security_api_integration/tests/session_idle/index.ts +++ b/x-pack/test/security_api_integration/tests/session_idle/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security APIs - Session Idle', function () { - this.tags('ciGroup6'); + this.tags('ciGroup18'); loadTestFile(require.resolve('./cleanup')); loadTestFile(require.resolve('./extension')); From 30de97bc2d8b8f9ec1f41dafdcef100e39c78ecf Mon Sep 17 00:00:00 2001 From: Brian Seeders Date: Wed, 10 Nov 2021 10:34:38 -0500 Subject: [PATCH 03/51] Revert "[CI] Rebalance/split cigroups and speed up overall CI time (#113676)" This reverts commit 9888b7fec3f84e76d8f32eb1757a71fa731c867d. --- .buildkite/pipelines/es_snapshots/verify.yml | 6 ++--- .buildkite/pipelines/flaky_tests/runner.js | 6 ++--- .buildkite/pipelines/hourly.yml | 12 +++++----- .buildkite/pipelines/pull_request/base.yml | 16 ++++++------- .../type_check_plugin_public_api_docs.sh | 24 +++---------------- .ci/ci_groups.yml | 14 ----------- test/functional/apps/management/index.ts | 2 +- test/functional/apps/visualize/index.ts | 4 ++-- .../security_and_spaces/tests/index.ts | 2 +- x-pack/test/api_integration/apis/index.ts | 4 ++-- .../api_integration/apis/security/index.ts | 2 +- .../test/api_integration/apis/spaces/index.ts | 2 +- .../security_and_spaces/tests/basic/index.ts | 2 +- .../security_and_spaces/tests/trial/index.ts | 3 ++- .../exception_operators_data_types/index.ts | 4 ++-- .../test/functional/apps/dashboard/index.ts | 2 +- x-pack/test/functional/apps/discover/index.ts | 2 +- x-pack/test/functional/apps/lens/index.ts | 13 ++++------ x-pack/test/functional/apps/maps/index.js | 8 ++----- x-pack/test/functional/apps/ml/index.ts | 21 +++++++--------- x-pack/test/functional/apps/security/index.ts | 2 +- .../test/functional/apps/transform/index.ts | 2 +- x-pack/test/functional_basic/apps/ml/index.ts | 2 +- .../security_and_spaces/apis/index.ts | 2 +- .../functional/tests/index.ts | 2 +- .../tests/kerberos/index.ts | 2 +- .../tests/saml/index.ts | 2 +- .../tests/session_idle/index.ts | 2 +- 28 files changed, 60 insertions(+), 105 deletions(-) diff --git a/.buildkite/pipelines/es_snapshots/verify.yml b/.buildkite/pipelines/es_snapshots/verify.yml index 93f8765ec16f7..9cddade0b7482 100755 --- a/.buildkite/pipelines/es_snapshots/verify.yml +++ b/.buildkite/pipelines/es_snapshots/verify.yml @@ -29,7 +29,7 @@ steps: label: 'Default CI Group' parallelism: 13 agents: - queue: n2-4 + queue: ci-group-6 depends_on: build timeout_in_minutes: 150 key: default-cigroup @@ -41,7 +41,7 @@ steps: - command: CI_GROUP=Docker .buildkite/scripts/steps/functional/xpack_cigroup.sh label: 'Docker CI Group' agents: - queue: n2-4 + queue: ci-group-6 depends_on: build timeout_in_minutes: 120 key: default-cigroup-docker @@ -77,7 +77,7 @@ steps: - command: .buildkite/scripts/steps/test/api_integration.sh label: 'API Integration Tests' agents: - queue: n2-2 + queue: jest timeout_in_minutes: 120 key: api-integration diff --git a/.buildkite/pipelines/flaky_tests/runner.js b/.buildkite/pipelines/flaky_tests/runner.js index 0c2db5c724f7b..b5ccab137fd01 100644 --- a/.buildkite/pipelines/flaky_tests/runner.js +++ b/.buildkite/pipelines/flaky_tests/runner.js @@ -78,7 +78,7 @@ for (const testSuite of testSuites) { steps.push({ command: `CI_GROUP=${CI_GROUP} .buildkite/scripts/steps/functional/xpack_cigroup.sh`, label: `Default CI Group ${CI_GROUP}`, - agents: { queue: 'n2-4' }, + agents: { queue: 'ci-group-6' }, depends_on: 'build', parallelism: RUN_COUNT, concurrency: concurrency, @@ -103,7 +103,7 @@ for (const testSuite of testSuites) { steps.push({ command: `.buildkite/scripts/steps/functional/${IS_XPACK ? 'xpack' : 'oss'}_firefox.sh`, label: `${IS_XPACK ? 'Default' : 'OSS'} Firefox`, - agents: { queue: IS_XPACK ? 'n2-4' : 'ci-group-4d' }, + agents: { queue: IS_XPACK ? 'ci-group-6' : 'ci-group-4d' }, depends_on: 'build', parallelism: RUN_COUNT, concurrency: concurrency, @@ -118,7 +118,7 @@ for (const testSuite of testSuites) { IS_XPACK ? 'xpack' : 'oss' }_accessibility.sh`, label: `${IS_XPACK ? 'Default' : 'OSS'} Accessibility`, - agents: { queue: IS_XPACK ? 'n2-4' : 'ci-group-4d' }, + agents: { queue: IS_XPACK ? 'ci-group-6' : 'ci-group-4d' }, depends_on: 'build', parallelism: RUN_COUNT, concurrency: concurrency, diff --git a/.buildkite/pipelines/hourly.yml b/.buildkite/pipelines/hourly.yml index 534300cce3988..9e9990816ad1d 100644 --- a/.buildkite/pipelines/hourly.yml +++ b/.buildkite/pipelines/hourly.yml @@ -19,7 +19,7 @@ steps: label: 'Default CI Group' parallelism: 13 agents: - queue: n2-4 + queue: ci-group-6 depends_on: build timeout_in_minutes: 250 key: default-cigroup @@ -31,7 +31,7 @@ steps: - command: CI_GROUP=Docker .buildkite/scripts/steps/functional/xpack_cigroup.sh label: 'Docker CI Group' agents: - queue: n2-4 + queue: ci-group-6 depends_on: build timeout_in_minutes: 120 key: default-cigroup-docker @@ -67,7 +67,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_accessibility.sh label: 'Default Accessibility Tests' agents: - queue: n2-4 + queue: ci-group-6 depends_on: build timeout_in_minutes: 120 retry: @@ -89,7 +89,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_firefox.sh label: 'Default Firefox Tests' agents: - queue: n2-4 + queue: ci-group-6 depends_on: build timeout_in_minutes: 120 retry: @@ -100,7 +100,7 @@ steps: - command: .buildkite/scripts/steps/functional/oss_misc.sh label: 'OSS Misc Functional Tests' agents: - queue: n2-4 + queue: ci-group-6 depends_on: build timeout_in_minutes: 120 retry: @@ -111,7 +111,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_saved_object_field_metrics.sh label: 'Saved Object Field Metrics' agents: - queue: n2-4 + queue: ci-group-6 depends_on: build timeout_in_minutes: 120 retry: diff --git a/.buildkite/pipelines/pull_request/base.yml b/.buildkite/pipelines/pull_request/base.yml index b99473c23d746..34db52772e619 100644 --- a/.buildkite/pipelines/pull_request/base.yml +++ b/.buildkite/pipelines/pull_request/base.yml @@ -15,9 +15,9 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_cigroup.sh label: 'Default CI Group' - parallelism: 27 + parallelism: 13 agents: - queue: n2-4 + queue: ci-group-6 depends_on: build timeout_in_minutes: 150 key: default-cigroup @@ -29,7 +29,7 @@ steps: - command: CI_GROUP=Docker .buildkite/scripts/steps/functional/xpack_cigroup.sh label: 'Docker CI Group' agents: - queue: n2-4 + queue: ci-group-6 depends_on: build timeout_in_minutes: 120 key: default-cigroup-docker @@ -65,7 +65,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_accessibility.sh label: 'Default Accessibility Tests' agents: - queue: n2-4 + queue: ci-group-6 depends_on: build timeout_in_minutes: 120 retry: @@ -87,7 +87,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_firefox.sh label: 'Default Firefox Tests' agents: - queue: n2-4 + queue: ci-group-6 depends_on: build timeout_in_minutes: 120 retry: @@ -98,7 +98,7 @@ steps: - command: .buildkite/scripts/steps/functional/oss_misc.sh label: 'OSS Misc Functional Tests' agents: - queue: n2-4 + queue: ci-group-6 depends_on: build timeout_in_minutes: 120 retry: @@ -109,7 +109,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_saved_object_field_metrics.sh label: 'Saved Object Field Metrics' agents: - queue: n2-4 + queue: ci-group-6 depends_on: build timeout_in_minutes: 120 retry: @@ -156,7 +156,7 @@ steps: - command: .buildkite/scripts/steps/checks.sh label: 'Checks' agents: - queue: c2-8 + queue: c2-4 key: checks timeout_in_minutes: 120 diff --git a/.buildkite/scripts/steps/checks/type_check_plugin_public_api_docs.sh b/.buildkite/scripts/steps/checks/type_check_plugin_public_api_docs.sh index 5827fd5eb2284..1d73d1748ddf7 100755 --- a/.buildkite/scripts/steps/checks/type_check_plugin_public_api_docs.sh +++ b/.buildkite/scripts/steps/checks/type_check_plugin_public_api_docs.sh @@ -11,27 +11,9 @@ checks-reporter-with-killswitch "Build TS Refs" \ --no-cache \ --force -checks-reporter-with-killswitch "Check Types" \ - node scripts/type_check &> target/check_types.log & -check_types_pid=$! - -node --max-old-space-size=12000 scripts/build_api_docs &> target/build_api_docs.log & -api_docs_pid=$! - -wait $check_types_pid -check_types_exit=$? - -wait $api_docs_pid -api_docs_exit=$? - echo --- Check Types -cat target/check_types.log -if [[ "$check_types_exit" != "0" ]]; then echo "^^^ +++"; fi +checks-reporter-with-killswitch "Check Types" \ + node scripts/type_check echo --- Building api docs -cat target/build_api_docs.log -if [[ "$api_docs_exit" != "0" ]]; then echo "^^^ +++"; fi - -if [[ "${api_docs_exit}${check_types_exit}" != "00" ]]; then - exit 1 -fi +node --max-old-space-size=12000 scripts/build_api_docs diff --git a/.ci/ci_groups.yml b/.ci/ci_groups.yml index 1be6e8c196a2d..9c3a039f51166 100644 --- a/.ci/ci_groups.yml +++ b/.ci/ci_groups.yml @@ -25,18 +25,4 @@ xpack: - ciGroup11 - ciGroup12 - ciGroup13 - - ciGroup14 - - ciGroup15 - - ciGroup16 - - ciGroup17 - - ciGroup18 - - ciGroup19 - - ciGroup20 - - ciGroup21 - - ciGroup22 - - ciGroup23 - - ciGroup24 - - ciGroup25 - - ciGroup26 - - ciGroup27 - ciGroupDocker diff --git a/test/functional/apps/management/index.ts b/test/functional/apps/management/index.ts index c906697021ecf..4787d7b9ee532 100644 --- a/test/functional/apps/management/index.ts +++ b/test/functional/apps/management/index.ts @@ -22,7 +22,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { }); describe('', function () { - this.tags('ciGroup9'); + this.tags('ciGroup7'); loadTestFile(require.resolve('./_create_index_pattern_wizard')); loadTestFile(require.resolve('./_index_pattern_create_delete')); diff --git a/test/functional/apps/visualize/index.ts b/test/functional/apps/visualize/index.ts index 68b95f3521a24..3bc4da0163909 100644 --- a/test/functional/apps/visualize/index.ts +++ b/test/functional/apps/visualize/index.ts @@ -74,8 +74,8 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_metric_chart')); }); - describe('visualize ciGroup1', function () { - this.tags('ciGroup1'); + describe('visualize ciGroup4', function () { + this.tags('ciGroup4'); loadTestFile(require.resolve('./_pie_chart')); loadTestFile(require.resolve('./_shared_item')); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts index 211fe9ec26863..a1f15c0db75fd 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts @@ -58,7 +58,7 @@ export async function tearDown(getService: FtrProviderContext['getService']) { // eslint-disable-next-line import/no-default-export export default function alertingApiIntegrationTests({ loadTestFile }: FtrProviderContext) { describe('alerting api integration security and spaces enabled', function () { - this.tags('ciGroup17'); + this.tags('ciGroup5'); loadTestFile(require.resolve('./actions')); loadTestFile(require.resolve('./alerting')); diff --git a/x-pack/test/api_integration/apis/index.ts b/x-pack/test/api_integration/apis/index.ts index 56b2042dc4854..c3d08ba306692 100644 --- a/x-pack/test/api_integration/apis/index.ts +++ b/x-pack/test/api_integration/apis/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('apis', function () { - this.tags('ciGroup18'); + this.tags('ciGroup6'); loadTestFile(require.resolve('./search')); loadTestFile(require.resolve('./es')); @@ -27,12 +27,12 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./maps')); loadTestFile(require.resolve('./security_solution')); loadTestFile(require.resolve('./lens')); + loadTestFile(require.resolve('./ml')); loadTestFile(require.resolve('./transform')); loadTestFile(require.resolve('./lists')); loadTestFile(require.resolve('./upgrade_assistant')); loadTestFile(require.resolve('./searchprofiler')); loadTestFile(require.resolve('./painless_lab')); loadTestFile(require.resolve('./file_upload')); - loadTestFile(require.resolve('./ml')); }); } diff --git a/x-pack/test/api_integration/apis/security/index.ts b/x-pack/test/api_integration/apis/security/index.ts index eb81d8245dbff..e190e02d9bdea 100644 --- a/x-pack/test/api_integration/apis/security/index.ts +++ b/x-pack/test/api_integration/apis/security/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security', function () { - this.tags('ciGroup18'); + this.tags('ciGroup6'); // Updates here should be mirrored in `./security_basic.ts` if tests // should also run under a basic license. diff --git a/x-pack/test/api_integration/apis/spaces/index.ts b/x-pack/test/api_integration/apis/spaces/index.ts index 3ca0040e39ec9..7267329249b22 100644 --- a/x-pack/test/api_integration/apis/spaces/index.ts +++ b/x-pack/test/api_integration/apis/spaces/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('spaces', function () { - this.tags('ciGroup18'); + this.tags('ciGroup6'); loadTestFile(require.resolve('./get_active_space')); loadTestFile(require.resolve('./saved_objects')); diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts index ce2f59a115e69..3fb7d7a29af39 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts @@ -12,7 +12,7 @@ import { createSpacesAndUsers, deleteSpacesAndUsers } from '../../../common/lib/ export default ({ loadTestFile, getService }: FtrProviderContext): void => { describe('cases security and spaces enabled: basic', function () { // Fastest ciGroup for the moment. - this.tags('ciGroup27'); + this.tags('ciGroup13'); before(async () => { await createSpacesAndUsers(getService); diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts index 1605003bf7015..cd4b062c065a0 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts @@ -11,7 +11,8 @@ import { createSpacesAndUsers, deleteSpacesAndUsers } from '../../../common/lib/ // eslint-disable-next-line import/no-default-export export default ({ loadTestFile, getService }: FtrProviderContext): void => { describe('cases security and spaces enabled: trial', function () { - this.tags('ciGroup25'); + // Fastest ciGroup for the moment. + this.tags('ciGroup13'); before(async () => { await createSpacesAndUsers(getService); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts index 85cc484146032..cebd20b698c26 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../../common/ftr_provider_context'; export default ({ loadTestFile }: FtrProviderContext): void => { describe('Detection exceptions data types and operators', function () { describe('', function () { - this.tags('ciGroup23'); + this.tags('ciGroup11'); loadTestFile(require.resolve('./date')); loadTestFile(require.resolve('./double')); @@ -20,7 +20,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => { }); describe('', function () { - this.tags('ciGroup24'); + this.tags('ciGroup12'); loadTestFile(require.resolve('./ip')); loadTestFile(require.resolve('./ip_array')); diff --git a/x-pack/test/functional/apps/dashboard/index.ts b/x-pack/test/functional/apps/dashboard/index.ts index 59211ecf37f2d..73c9b83de917f 100644 --- a/x-pack/test/functional/apps/dashboard/index.ts +++ b/x-pack/test/functional/apps/dashboard/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('dashboard', function () { - this.tags('ciGroup19'); + this.tags('ciGroup7'); loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./preserve_url')); diff --git a/x-pack/test/functional/apps/discover/index.ts b/x-pack/test/functional/apps/discover/index.ts index 9eda11bc6e6fb..af117a2182034 100644 --- a/x-pack/test/functional/apps/discover/index.ts +++ b/x-pack/test/functional/apps/discover/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('discover', function () { - this.tags('ciGroup25'); + this.tags('ciGroup1'); loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./preserve_url')); diff --git a/x-pack/test/functional/apps/lens/index.ts b/x-pack/test/functional/apps/lens/index.ts index 79f9b8f645c1a..f9e4835f044af 100644 --- a/x-pack/test/functional/apps/lens/index.ts +++ b/x-pack/test/functional/apps/lens/index.ts @@ -50,6 +50,10 @@ export default function ({ getService, loadTestFile, getPageObjects }: FtrProvid describe('', function () { this.tags(['ciGroup4', 'skipFirefox']); + loadTestFile(require.resolve('./add_to_dashboard')); + loadTestFile(require.resolve('./table')); + loadTestFile(require.resolve('./runtime_fields')); + loadTestFile(require.resolve('./dashboard')); loadTestFile(require.resolve('./colors')); loadTestFile(require.resolve('./chart_data')); loadTestFile(require.resolve('./time_shift')); @@ -65,14 +69,5 @@ export default function ({ getService, loadTestFile, getPageObjects }: FtrProvid // has to be last one in the suite because it overrides saved objects loadTestFile(require.resolve('./rollup')); }); - - describe('', function () { - this.tags(['ciGroup16', 'skipFirefox']); - - loadTestFile(require.resolve('./add_to_dashboard')); - loadTestFile(require.resolve('./table')); - loadTestFile(require.resolve('./runtime_fields')); - loadTestFile(require.resolve('./dashboard')); - }); }); } diff --git a/x-pack/test/functional/apps/maps/index.js b/x-pack/test/functional/apps/maps/index.js index b85859bf2d5d3..6a2a843682f26 100644 --- a/x-pack/test/functional/apps/maps/index.js +++ b/x-pack/test/functional/apps/maps/index.js @@ -72,14 +72,9 @@ export default function ({ loadTestFile, getService }) { loadTestFile(require.resolve('./full_screen_mode')); }); - describe('', function () { - this.tags('ciGroup22'); - loadTestFile(require.resolve('./es_geo_grid_source')); - loadTestFile(require.resolve('./embeddable')); - }); - describe('', function () { this.tags('ciGroup10'); + loadTestFile(require.resolve('./es_geo_grid_source')); loadTestFile(require.resolve('./es_pew_pew_source')); loadTestFile(require.resolve('./joins')); loadTestFile(require.resolve('./mapbox_styles')); @@ -88,6 +83,7 @@ export default function ({ loadTestFile, getService }) { loadTestFile(require.resolve('./add_layer_panel')); loadTestFile(require.resolve('./import_geojson')); loadTestFile(require.resolve('./layer_errors')); + loadTestFile(require.resolve('./embeddable')); loadTestFile(require.resolve('./visualize_create_menu')); loadTestFile(require.resolve('./discover')); }); diff --git a/x-pack/test/functional/apps/ml/index.ts b/x-pack/test/functional/apps/ml/index.ts index 493813daa4f72..2e3a29d50dd11 100644 --- a/x-pack/test/functional/apps/ml/index.ts +++ b/x-pack/test/functional/apps/ml/index.ts @@ -13,6 +13,8 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { describe('machine learning', function () { describe('', function () { + this.tags('ciGroup3'); + before(async () => { await ml.securityCommon.createMlRoles(); await ml.securityCommon.createMlUsers(); @@ -45,19 +47,12 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await ml.testResources.resetKibanaTimeZone(); }); - describe('', function () { - this.tags('ciGroup15'); - loadTestFile(require.resolve('./permissions')); - loadTestFile(require.resolve('./pages')); - loadTestFile(require.resolve('./data_visualizer')); - loadTestFile(require.resolve('./data_frame_analytics')); - loadTestFile(require.resolve('./model_management')); - }); - - describe('', function () { - this.tags('ciGroup26'); - loadTestFile(require.resolve('./anomaly_detection')); - }); + loadTestFile(require.resolve('./permissions')); + loadTestFile(require.resolve('./pages')); + loadTestFile(require.resolve('./anomaly_detection')); + loadTestFile(require.resolve('./data_visualizer')); + loadTestFile(require.resolve('./data_frame_analytics')); + loadTestFile(require.resolve('./model_management')); }); describe('', function () { diff --git a/x-pack/test/functional/apps/security/index.ts b/x-pack/test/functional/apps/security/index.ts index fc9caafbabb29..3b4c6989d38fa 100644 --- a/x-pack/test/functional/apps/security/index.ts +++ b/x-pack/test/functional/apps/security/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security app', function () { - this.tags('ciGroup7'); + this.tags('ciGroup4'); loadTestFile(require.resolve('./security')); loadTestFile(require.resolve('./doc_level_security_roles')); diff --git a/x-pack/test/functional/apps/transform/index.ts b/x-pack/test/functional/apps/transform/index.ts index 4a9aafb072852..90bb95fd6b3e8 100644 --- a/x-pack/test/functional/apps/transform/index.ts +++ b/x-pack/test/functional/apps/transform/index.ts @@ -16,7 +16,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { const transform = getService('transform'); describe('transform', function () { - this.tags(['ciGroup21', 'transform']); + this.tags(['ciGroup9', 'transform']); before(async () => { await transform.securityCommon.createTransformRoles(); diff --git a/x-pack/test/functional_basic/apps/ml/index.ts b/x-pack/test/functional_basic/apps/ml/index.ts index af2fdc8c45f29..ed1ab4f417584 100644 --- a/x-pack/test/functional_basic/apps/ml/index.ts +++ b/x-pack/test/functional_basic/apps/ml/index.ts @@ -12,7 +12,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { const ml = getService('ml'); describe('machine learning basic license', function () { - this.tags(['ciGroup14', 'skipFirefox', 'mlqa']); + this.tags(['ciGroup2', 'skipFirefox', 'mlqa']); before(async () => { await ml.securityCommon.createMlRoles(); diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts index 740b9d91927bf..5412f9d9bdfed 100644 --- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts +++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts @@ -13,7 +13,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { const supertest = getService('supertest'); describe('saved objects security and spaces enabled', function () { - this.tags('ciGroup20'); + this.tags('ciGroup8'); before(async () => { await createUsersAndRoles(es, supertest); diff --git a/x-pack/test/saved_object_tagging/functional/tests/index.ts b/x-pack/test/saved_object_tagging/functional/tests/index.ts index fbf0954382dd1..7a82574f34b6e 100644 --- a/x-pack/test/saved_object_tagging/functional/tests/index.ts +++ b/x-pack/test/saved_object_tagging/functional/tests/index.ts @@ -11,7 +11,7 @@ import { createUsersAndRoles } from '../../common/lib'; // eslint-disable-next-line import/no-default-export export default function ({ loadTestFile, getService }: FtrProviderContext) { describe('saved objects tagging - functional tests', function () { - this.tags('ciGroup14'); + this.tags('ciGroup2'); before(async () => { await createUsersAndRoles(getService); diff --git a/x-pack/test/security_api_integration/tests/kerberos/index.ts b/x-pack/test/security_api_integration/tests/kerberos/index.ts index 39aac8cc4ca2f..3faec0badd89e 100644 --- a/x-pack/test/security_api_integration/tests/kerberos/index.ts +++ b/x-pack/test/security_api_integration/tests/kerberos/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security APIs - Kerberos', function () { - this.tags('ciGroup16'); + this.tags('ciGroup6'); loadTestFile(require.resolve('./kerberos_login')); }); diff --git a/x-pack/test/security_api_integration/tests/saml/index.ts b/x-pack/test/security_api_integration/tests/saml/index.ts index dbabb835ee980..375864c71432d 100644 --- a/x-pack/test/security_api_integration/tests/saml/index.ts +++ b/x-pack/test/security_api_integration/tests/saml/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security APIs - SAML', function () { - this.tags('ciGroup18'); + this.tags('ciGroup6'); loadTestFile(require.resolve('./saml_login')); }); diff --git a/x-pack/test/security_api_integration/tests/session_idle/index.ts b/x-pack/test/security_api_integration/tests/session_idle/index.ts index 76457ee7ad0c7..bbf811de70db4 100644 --- a/x-pack/test/security_api_integration/tests/session_idle/index.ts +++ b/x-pack/test/security_api_integration/tests/session_idle/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security APIs - Session Idle', function () { - this.tags('ciGroup18'); + this.tags('ciGroup6'); loadTestFile(require.resolve('./cleanup')); loadTestFile(require.resolve('./extension')); From 60a922152741a9d197fcb083381481c705ca2e96 Mon Sep 17 00:00:00 2001 From: Dmitry Shevchenko Date: Wed, 10 Nov 2021 17:16:44 +0100 Subject: [PATCH 04/51] Add missing await (#118171) --- .../rule_execution_log/event_log_adapter/event_log_adapter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/event_log_adapter.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/event_log_adapter.ts index e5660da8d4cf4..8b55339aa9f02 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/event_log_adapter.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/event_log_adapter.ts @@ -104,7 +104,7 @@ export class EventLogAdapter implements IRuleExecutionLogClient { await this.savedObjectsAdapter.logStatusChange(args); if (args.metrics) { - this.logExecutionMetrics({ + await this.logExecutionMetrics({ ruleId: args.ruleId, ruleName: args.ruleName, ruleType: args.ruleType, From 5cccf0cdd6ce3a7601ab3a0c0b04edab6db1bae1 Mon Sep 17 00:00:00 2001 From: Michael Dokolin Date: Wed, 10 Nov 2021 17:17:07 +0100 Subject: [PATCH 05/51] [Reporting] Optimize visualizations awaiter performance (#118012) --- .../chromium/driver/chromium_driver.ts | 40 +++++-------------- .../screenshots/wait_for_visualizations.ts | 29 ++++++++++---- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/x-pack/plugins/reporting/server/browsers/chromium/driver/chromium_driver.ts b/x-pack/plugins/reporting/server/browsers/chromium/driver/chromium_driver.ts index e7c2b68ba2712..0947d24f827c2 100644 --- a/x-pack/plugins/reporting/server/browsers/chromium/driver/chromium_driver.ts +++ b/x-pack/plugins/reporting/server/browsers/chromium/driver/chromium_driver.ts @@ -210,36 +210,16 @@ export class HeadlessChromiumDriver { return resp; } - public async waitFor( - { - fn, - args, - toEqual, - timeout, - }: { - fn: EvaluateFn; - args: SerializableOrJSHandle[]; - toEqual: number; - timeout: number; - }, - context: EvaluateMetaOpts, - logger: LevelLogger - ): Promise { - const startTime = Date.now(); - - while (true) { - const result = await this.evaluate({ fn, args }, context, logger); - if (result === toEqual) { - return; - } - - if (Date.now() - startTime > timeout) { - throw new Error( - `Timed out waiting for the items selected to equal ${toEqual}. Found: ${result}. Context: ${context.context}` - ); - } - await new Promise((r) => setTimeout(r, WAIT_FOR_DELAY_MS)); - } + public async waitFor({ + fn, + args, + timeout, + }: { + fn: EvaluateFn; + args: SerializableOrJSHandle[]; + timeout: number; + }): Promise { + await this.page.waitForFunction(fn, { timeout, polling: WAIT_FOR_DELAY_MS }, ...args); } public async setViewport( diff --git a/x-pack/plugins/reporting/server/lib/screenshots/wait_for_visualizations.ts b/x-pack/plugins/reporting/server/lib/screenshots/wait_for_visualizations.ts index d4bf1db2a0c5a..10a53b238d892 100644 --- a/x-pack/plugins/reporting/server/lib/screenshots/wait_for_visualizations.ts +++ b/x-pack/plugins/reporting/server/lib/screenshots/wait_for_visualizations.ts @@ -11,10 +11,23 @@ import { HeadlessChromiumDriver } from '../../browsers'; import { LayoutInstance } from '../layouts'; import { CONTEXT_WAITFORELEMENTSTOBEINDOM } from './constants'; -type SelectorArgs = Record; +interface CompletedItemsCountParameters { + context: string; + count: number; + renderCompleteSelector: string; +} -const getCompletedItemsCount = ({ renderCompleteSelector }: SelectorArgs) => { - return document.querySelectorAll(renderCompleteSelector).length; +const getCompletedItemsCount = ({ + context, + count, + renderCompleteSelector, +}: CompletedItemsCountParameters) => { + const { length } = document.querySelectorAll(renderCompleteSelector); + + // eslint-disable-next-line no-console + console.debug(`evaluate ${context}: waitng for ${count} elements, got ${length}.`); + + return length >= count; }; /* @@ -40,11 +53,11 @@ export const waitForVisualizations = async ( ); try { - await browser.waitFor( - { fn: getCompletedItemsCount, args: [{ renderCompleteSelector }], toEqual, timeout }, - { context: CONTEXT_WAITFORELEMENTSTOBEINDOM }, - logger - ); + await browser.waitFor({ + fn: getCompletedItemsCount, + args: [{ renderCompleteSelector, context: CONTEXT_WAITFORELEMENTSTOBEINDOM, count: toEqual }], + timeout, + }); logger.debug(`found ${toEqual} rendered elements in the DOM`); } catch (err) { From 68f46a5c8ebe0fb44e9ef140eeebb25c25a73f44 Mon Sep 17 00:00:00 2001 From: Vadim Yakhin Date: Wed, 10 Nov 2021 08:48:57 -0800 Subject: [PATCH 06/51] Update web crawler link to lead directly to the crawler page (#118111) --- .../sections/epm/screens/home/available_packages.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx index e54ab0d9ecd46..62f911ffdbbb7 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx @@ -348,7 +348,7 @@ export const AvailablePackages: React.FC = memo(() => { } - href={addBasePath('/app/enterprise_search/app_search')} + href={addBasePath('/app/enterprise_search/app_search/engines/new?method=crawler')} title={i18n.translate('xpack.fleet.featuredSearchTitle', { defaultMessage: 'Web site crawler', })} From 8ba9ebf59294266f41264248a94f3bb420d9de4c Mon Sep 17 00:00:00 2001 From: Brian Seeders Date: Wed, 10 Nov 2021 12:01:03 -0500 Subject: [PATCH 07/51] [CI] Rebalance/split cigroups and speed up overall CI time (#118191) --- .buildkite/pipelines/es_snapshots/verify.yml | 8 +++---- .buildkite/pipelines/flaky_tests/pipeline.js | 2 +- .buildkite/pipelines/flaky_tests/runner.js | 6 ++--- .buildkite/pipelines/hourly.yml | 14 +++++------ .buildkite/pipelines/pull_request/base.yml | 16 ++++++------- .../type_check_plugin_public_api_docs.sh | 24 ++++++++++++++++--- .ci/ci_groups.yml | 14 +++++++++++ test/functional/apps/management/index.ts | 2 +- test/functional/apps/visualize/index.ts | 4 ++-- .../security_and_spaces/tests/index.ts | 2 +- x-pack/test/api_integration/apis/index.ts | 4 ++-- .../api_integration/apis/security/index.ts | 2 +- .../test/api_integration/apis/spaces/index.ts | 2 +- .../security_and_spaces/tests/basic/index.ts | 2 +- .../security_and_spaces/tests/trial/index.ts | 3 +-- .../exception_operators_data_types/index.ts | 4 ++-- .../test/functional/apps/dashboard/index.ts | 2 +- x-pack/test/functional/apps/discover/index.ts | 2 +- x-pack/test/functional/apps/lens/index.ts | 13 ++++++---- x-pack/test/functional/apps/maps/index.js | 8 +++++-- x-pack/test/functional/apps/ml/index.ts | 21 +++++++++------- x-pack/test/functional/apps/security/index.ts | 2 +- .../test/functional/apps/transform/index.ts | 2 +- x-pack/test/functional_basic/apps/ml/index.ts | 2 +- .../security_and_spaces/apis/index.ts | 2 +- .../functional/tests/index.ts | 2 +- .../tests/kerberos/index.ts | 2 +- .../tests/saml/index.ts | 2 +- .../tests/session_idle/index.ts | 2 +- 29 files changed, 108 insertions(+), 63 deletions(-) diff --git a/.buildkite/pipelines/es_snapshots/verify.yml b/.buildkite/pipelines/es_snapshots/verify.yml index 9cddade0b7482..7d700b1e0f489 100755 --- a/.buildkite/pipelines/es_snapshots/verify.yml +++ b/.buildkite/pipelines/es_snapshots/verify.yml @@ -27,9 +27,9 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_cigroup.sh label: 'Default CI Group' - parallelism: 13 + parallelism: 27 agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 150 key: default-cigroup @@ -41,7 +41,7 @@ steps: - command: CI_GROUP=Docker .buildkite/scripts/steps/functional/xpack_cigroup.sh label: 'Docker CI Group' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 key: default-cigroup-docker @@ -77,7 +77,7 @@ steps: - command: .buildkite/scripts/steps/test/api_integration.sh label: 'API Integration Tests' agents: - queue: jest + queue: n2-2 timeout_in_minutes: 120 key: api-integration diff --git a/.buildkite/pipelines/flaky_tests/pipeline.js b/.buildkite/pipelines/flaky_tests/pipeline.js index 37e8a97406eb5..bf4abb9ff4c89 100644 --- a/.buildkite/pipelines/flaky_tests/pipeline.js +++ b/.buildkite/pipelines/flaky_tests/pipeline.js @@ -8,7 +8,7 @@ const stepInput = (key, nameOfSuite) => { }; const OSS_CI_GROUPS = 12; -const XPACK_CI_GROUPS = 13; +const XPACK_CI_GROUPS = 27; const inputs = [ { diff --git a/.buildkite/pipelines/flaky_tests/runner.js b/.buildkite/pipelines/flaky_tests/runner.js index b5ccab137fd01..0c2db5c724f7b 100644 --- a/.buildkite/pipelines/flaky_tests/runner.js +++ b/.buildkite/pipelines/flaky_tests/runner.js @@ -78,7 +78,7 @@ for (const testSuite of testSuites) { steps.push({ command: `CI_GROUP=${CI_GROUP} .buildkite/scripts/steps/functional/xpack_cigroup.sh`, label: `Default CI Group ${CI_GROUP}`, - agents: { queue: 'ci-group-6' }, + agents: { queue: 'n2-4' }, depends_on: 'build', parallelism: RUN_COUNT, concurrency: concurrency, @@ -103,7 +103,7 @@ for (const testSuite of testSuites) { steps.push({ command: `.buildkite/scripts/steps/functional/${IS_XPACK ? 'xpack' : 'oss'}_firefox.sh`, label: `${IS_XPACK ? 'Default' : 'OSS'} Firefox`, - agents: { queue: IS_XPACK ? 'ci-group-6' : 'ci-group-4d' }, + agents: { queue: IS_XPACK ? 'n2-4' : 'ci-group-4d' }, depends_on: 'build', parallelism: RUN_COUNT, concurrency: concurrency, @@ -118,7 +118,7 @@ for (const testSuite of testSuites) { IS_XPACK ? 'xpack' : 'oss' }_accessibility.sh`, label: `${IS_XPACK ? 'Default' : 'OSS'} Accessibility`, - agents: { queue: IS_XPACK ? 'ci-group-6' : 'ci-group-4d' }, + agents: { queue: IS_XPACK ? 'n2-4' : 'ci-group-4d' }, depends_on: 'build', parallelism: RUN_COUNT, concurrency: concurrency, diff --git a/.buildkite/pipelines/hourly.yml b/.buildkite/pipelines/hourly.yml index 9e9990816ad1d..bc9644820784d 100644 --- a/.buildkite/pipelines/hourly.yml +++ b/.buildkite/pipelines/hourly.yml @@ -17,9 +17,9 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_cigroup.sh label: 'Default CI Group' - parallelism: 13 + parallelism: 27 agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 250 key: default-cigroup @@ -31,7 +31,7 @@ steps: - command: CI_GROUP=Docker .buildkite/scripts/steps/functional/xpack_cigroup.sh label: 'Docker CI Group' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 key: default-cigroup-docker @@ -67,7 +67,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_accessibility.sh label: 'Default Accessibility Tests' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: @@ -89,7 +89,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_firefox.sh label: 'Default Firefox Tests' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: @@ -100,7 +100,7 @@ steps: - command: .buildkite/scripts/steps/functional/oss_misc.sh label: 'OSS Misc Functional Tests' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: @@ -111,7 +111,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_saved_object_field_metrics.sh label: 'Saved Object Field Metrics' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: diff --git a/.buildkite/pipelines/pull_request/base.yml b/.buildkite/pipelines/pull_request/base.yml index 34db52772e619..b99473c23d746 100644 --- a/.buildkite/pipelines/pull_request/base.yml +++ b/.buildkite/pipelines/pull_request/base.yml @@ -15,9 +15,9 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_cigroup.sh label: 'Default CI Group' - parallelism: 13 + parallelism: 27 agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 150 key: default-cigroup @@ -29,7 +29,7 @@ steps: - command: CI_GROUP=Docker .buildkite/scripts/steps/functional/xpack_cigroup.sh label: 'Docker CI Group' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 key: default-cigroup-docker @@ -65,7 +65,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_accessibility.sh label: 'Default Accessibility Tests' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: @@ -87,7 +87,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_firefox.sh label: 'Default Firefox Tests' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: @@ -98,7 +98,7 @@ steps: - command: .buildkite/scripts/steps/functional/oss_misc.sh label: 'OSS Misc Functional Tests' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: @@ -109,7 +109,7 @@ steps: - command: .buildkite/scripts/steps/functional/xpack_saved_object_field_metrics.sh label: 'Saved Object Field Metrics' agents: - queue: ci-group-6 + queue: n2-4 depends_on: build timeout_in_minutes: 120 retry: @@ -156,7 +156,7 @@ steps: - command: .buildkite/scripts/steps/checks.sh label: 'Checks' agents: - queue: c2-4 + queue: c2-8 key: checks timeout_in_minutes: 120 diff --git a/.buildkite/scripts/steps/checks/type_check_plugin_public_api_docs.sh b/.buildkite/scripts/steps/checks/type_check_plugin_public_api_docs.sh index 1d73d1748ddf7..5827fd5eb2284 100755 --- a/.buildkite/scripts/steps/checks/type_check_plugin_public_api_docs.sh +++ b/.buildkite/scripts/steps/checks/type_check_plugin_public_api_docs.sh @@ -11,9 +11,27 @@ checks-reporter-with-killswitch "Build TS Refs" \ --no-cache \ --force -echo --- Check Types checks-reporter-with-killswitch "Check Types" \ - node scripts/type_check + node scripts/type_check &> target/check_types.log & +check_types_pid=$! + +node --max-old-space-size=12000 scripts/build_api_docs &> target/build_api_docs.log & +api_docs_pid=$! + +wait $check_types_pid +check_types_exit=$? + +wait $api_docs_pid +api_docs_exit=$? + +echo --- Check Types +cat target/check_types.log +if [[ "$check_types_exit" != "0" ]]; then echo "^^^ +++"; fi echo --- Building api docs -node --max-old-space-size=12000 scripts/build_api_docs +cat target/build_api_docs.log +if [[ "$api_docs_exit" != "0" ]]; then echo "^^^ +++"; fi + +if [[ "${api_docs_exit}${check_types_exit}" != "00" ]]; then + exit 1 +fi diff --git a/.ci/ci_groups.yml b/.ci/ci_groups.yml index 9c3a039f51166..1be6e8c196a2d 100644 --- a/.ci/ci_groups.yml +++ b/.ci/ci_groups.yml @@ -25,4 +25,18 @@ xpack: - ciGroup11 - ciGroup12 - ciGroup13 + - ciGroup14 + - ciGroup15 + - ciGroup16 + - ciGroup17 + - ciGroup18 + - ciGroup19 + - ciGroup20 + - ciGroup21 + - ciGroup22 + - ciGroup23 + - ciGroup24 + - ciGroup25 + - ciGroup26 + - ciGroup27 - ciGroupDocker diff --git a/test/functional/apps/management/index.ts b/test/functional/apps/management/index.ts index 4787d7b9ee532..c906697021ecf 100644 --- a/test/functional/apps/management/index.ts +++ b/test/functional/apps/management/index.ts @@ -22,7 +22,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { }); describe('', function () { - this.tags('ciGroup7'); + this.tags('ciGroup9'); loadTestFile(require.resolve('./_create_index_pattern_wizard')); loadTestFile(require.resolve('./_index_pattern_create_delete')); diff --git a/test/functional/apps/visualize/index.ts b/test/functional/apps/visualize/index.ts index 3bc4da0163909..68b95f3521a24 100644 --- a/test/functional/apps/visualize/index.ts +++ b/test/functional/apps/visualize/index.ts @@ -74,8 +74,8 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_metric_chart')); }); - describe('visualize ciGroup4', function () { - this.tags('ciGroup4'); + describe('visualize ciGroup1', function () { + this.tags('ciGroup1'); loadTestFile(require.resolve('./_pie_chart')); loadTestFile(require.resolve('./_shared_item')); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts index a1f15c0db75fd..211fe9ec26863 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts @@ -58,7 +58,7 @@ export async function tearDown(getService: FtrProviderContext['getService']) { // eslint-disable-next-line import/no-default-export export default function alertingApiIntegrationTests({ loadTestFile }: FtrProviderContext) { describe('alerting api integration security and spaces enabled', function () { - this.tags('ciGroup5'); + this.tags('ciGroup17'); loadTestFile(require.resolve('./actions')); loadTestFile(require.resolve('./alerting')); diff --git a/x-pack/test/api_integration/apis/index.ts b/x-pack/test/api_integration/apis/index.ts index c3d08ba306692..56b2042dc4854 100644 --- a/x-pack/test/api_integration/apis/index.ts +++ b/x-pack/test/api_integration/apis/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('apis', function () { - this.tags('ciGroup6'); + this.tags('ciGroup18'); loadTestFile(require.resolve('./search')); loadTestFile(require.resolve('./es')); @@ -27,12 +27,12 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./maps')); loadTestFile(require.resolve('./security_solution')); loadTestFile(require.resolve('./lens')); - loadTestFile(require.resolve('./ml')); loadTestFile(require.resolve('./transform')); loadTestFile(require.resolve('./lists')); loadTestFile(require.resolve('./upgrade_assistant')); loadTestFile(require.resolve('./searchprofiler')); loadTestFile(require.resolve('./painless_lab')); loadTestFile(require.resolve('./file_upload')); + loadTestFile(require.resolve('./ml')); }); } diff --git a/x-pack/test/api_integration/apis/security/index.ts b/x-pack/test/api_integration/apis/security/index.ts index e190e02d9bdea..eb81d8245dbff 100644 --- a/x-pack/test/api_integration/apis/security/index.ts +++ b/x-pack/test/api_integration/apis/security/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security', function () { - this.tags('ciGroup6'); + this.tags('ciGroup18'); // Updates here should be mirrored in `./security_basic.ts` if tests // should also run under a basic license. diff --git a/x-pack/test/api_integration/apis/spaces/index.ts b/x-pack/test/api_integration/apis/spaces/index.ts index 7267329249b22..3ca0040e39ec9 100644 --- a/x-pack/test/api_integration/apis/spaces/index.ts +++ b/x-pack/test/api_integration/apis/spaces/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('spaces', function () { - this.tags('ciGroup6'); + this.tags('ciGroup18'); loadTestFile(require.resolve('./get_active_space')); loadTestFile(require.resolve('./saved_objects')); diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts index 3fb7d7a29af39..ce2f59a115e69 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts @@ -12,7 +12,7 @@ import { createSpacesAndUsers, deleteSpacesAndUsers } from '../../../common/lib/ export default ({ loadTestFile, getService }: FtrProviderContext): void => { describe('cases security and spaces enabled: basic', function () { // Fastest ciGroup for the moment. - this.tags('ciGroup13'); + this.tags('ciGroup27'); before(async () => { await createSpacesAndUsers(getService); diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts index cd4b062c065a0..1605003bf7015 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts @@ -11,8 +11,7 @@ import { createSpacesAndUsers, deleteSpacesAndUsers } from '../../../common/lib/ // eslint-disable-next-line import/no-default-export export default ({ loadTestFile, getService }: FtrProviderContext): void => { describe('cases security and spaces enabled: trial', function () { - // Fastest ciGroup for the moment. - this.tags('ciGroup13'); + this.tags('ciGroup25'); before(async () => { await createSpacesAndUsers(getService); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts index cebd20b698c26..85cc484146032 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../../common/ftr_provider_context'; export default ({ loadTestFile }: FtrProviderContext): void => { describe('Detection exceptions data types and operators', function () { describe('', function () { - this.tags('ciGroup11'); + this.tags('ciGroup23'); loadTestFile(require.resolve('./date')); loadTestFile(require.resolve('./double')); @@ -20,7 +20,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => { }); describe('', function () { - this.tags('ciGroup12'); + this.tags('ciGroup24'); loadTestFile(require.resolve('./ip')); loadTestFile(require.resolve('./ip_array')); diff --git a/x-pack/test/functional/apps/dashboard/index.ts b/x-pack/test/functional/apps/dashboard/index.ts index 73c9b83de917f..59211ecf37f2d 100644 --- a/x-pack/test/functional/apps/dashboard/index.ts +++ b/x-pack/test/functional/apps/dashboard/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('dashboard', function () { - this.tags('ciGroup7'); + this.tags('ciGroup19'); loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./preserve_url')); diff --git a/x-pack/test/functional/apps/discover/index.ts b/x-pack/test/functional/apps/discover/index.ts index af117a2182034..9eda11bc6e6fb 100644 --- a/x-pack/test/functional/apps/discover/index.ts +++ b/x-pack/test/functional/apps/discover/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('discover', function () { - this.tags('ciGroup1'); + this.tags('ciGroup25'); loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./preserve_url')); diff --git a/x-pack/test/functional/apps/lens/index.ts b/x-pack/test/functional/apps/lens/index.ts index f9e4835f044af..79f9b8f645c1a 100644 --- a/x-pack/test/functional/apps/lens/index.ts +++ b/x-pack/test/functional/apps/lens/index.ts @@ -50,10 +50,6 @@ export default function ({ getService, loadTestFile, getPageObjects }: FtrProvid describe('', function () { this.tags(['ciGroup4', 'skipFirefox']); - loadTestFile(require.resolve('./add_to_dashboard')); - loadTestFile(require.resolve('./table')); - loadTestFile(require.resolve('./runtime_fields')); - loadTestFile(require.resolve('./dashboard')); loadTestFile(require.resolve('./colors')); loadTestFile(require.resolve('./chart_data')); loadTestFile(require.resolve('./time_shift')); @@ -69,5 +65,14 @@ export default function ({ getService, loadTestFile, getPageObjects }: FtrProvid // has to be last one in the suite because it overrides saved objects loadTestFile(require.resolve('./rollup')); }); + + describe('', function () { + this.tags(['ciGroup16', 'skipFirefox']); + + loadTestFile(require.resolve('./add_to_dashboard')); + loadTestFile(require.resolve('./table')); + loadTestFile(require.resolve('./runtime_fields')); + loadTestFile(require.resolve('./dashboard')); + }); }); } diff --git a/x-pack/test/functional/apps/maps/index.js b/x-pack/test/functional/apps/maps/index.js index 6a2a843682f26..b85859bf2d5d3 100644 --- a/x-pack/test/functional/apps/maps/index.js +++ b/x-pack/test/functional/apps/maps/index.js @@ -73,8 +73,13 @@ export default function ({ loadTestFile, getService }) { }); describe('', function () { - this.tags('ciGroup10'); + this.tags('ciGroup22'); loadTestFile(require.resolve('./es_geo_grid_source')); + loadTestFile(require.resolve('./embeddable')); + }); + + describe('', function () { + this.tags('ciGroup10'); loadTestFile(require.resolve('./es_pew_pew_source')); loadTestFile(require.resolve('./joins')); loadTestFile(require.resolve('./mapbox_styles')); @@ -83,7 +88,6 @@ export default function ({ loadTestFile, getService }) { loadTestFile(require.resolve('./add_layer_panel')); loadTestFile(require.resolve('./import_geojson')); loadTestFile(require.resolve('./layer_errors')); - loadTestFile(require.resolve('./embeddable')); loadTestFile(require.resolve('./visualize_create_menu')); loadTestFile(require.resolve('./discover')); }); diff --git a/x-pack/test/functional/apps/ml/index.ts b/x-pack/test/functional/apps/ml/index.ts index 2e3a29d50dd11..493813daa4f72 100644 --- a/x-pack/test/functional/apps/ml/index.ts +++ b/x-pack/test/functional/apps/ml/index.ts @@ -13,8 +13,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { describe('machine learning', function () { describe('', function () { - this.tags('ciGroup3'); - before(async () => { await ml.securityCommon.createMlRoles(); await ml.securityCommon.createMlUsers(); @@ -47,12 +45,19 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await ml.testResources.resetKibanaTimeZone(); }); - loadTestFile(require.resolve('./permissions')); - loadTestFile(require.resolve('./pages')); - loadTestFile(require.resolve('./anomaly_detection')); - loadTestFile(require.resolve('./data_visualizer')); - loadTestFile(require.resolve('./data_frame_analytics')); - loadTestFile(require.resolve('./model_management')); + describe('', function () { + this.tags('ciGroup15'); + loadTestFile(require.resolve('./permissions')); + loadTestFile(require.resolve('./pages')); + loadTestFile(require.resolve('./data_visualizer')); + loadTestFile(require.resolve('./data_frame_analytics')); + loadTestFile(require.resolve('./model_management')); + }); + + describe('', function () { + this.tags('ciGroup26'); + loadTestFile(require.resolve('./anomaly_detection')); + }); }); describe('', function () { diff --git a/x-pack/test/functional/apps/security/index.ts b/x-pack/test/functional/apps/security/index.ts index 3b4c6989d38fa..fc9caafbabb29 100644 --- a/x-pack/test/functional/apps/security/index.ts +++ b/x-pack/test/functional/apps/security/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security app', function () { - this.tags('ciGroup4'); + this.tags('ciGroup7'); loadTestFile(require.resolve('./security')); loadTestFile(require.resolve('./doc_level_security_roles')); diff --git a/x-pack/test/functional/apps/transform/index.ts b/x-pack/test/functional/apps/transform/index.ts index 90bb95fd6b3e8..4a9aafb072852 100644 --- a/x-pack/test/functional/apps/transform/index.ts +++ b/x-pack/test/functional/apps/transform/index.ts @@ -16,7 +16,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { const transform = getService('transform'); describe('transform', function () { - this.tags(['ciGroup9', 'transform']); + this.tags(['ciGroup21', 'transform']); before(async () => { await transform.securityCommon.createTransformRoles(); diff --git a/x-pack/test/functional_basic/apps/ml/index.ts b/x-pack/test/functional_basic/apps/ml/index.ts index ed1ab4f417584..af2fdc8c45f29 100644 --- a/x-pack/test/functional_basic/apps/ml/index.ts +++ b/x-pack/test/functional_basic/apps/ml/index.ts @@ -12,7 +12,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { const ml = getService('ml'); describe('machine learning basic license', function () { - this.tags(['ciGroup2', 'skipFirefox', 'mlqa']); + this.tags(['ciGroup14', 'skipFirefox', 'mlqa']); before(async () => { await ml.securityCommon.createMlRoles(); diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts index 5412f9d9bdfed..740b9d91927bf 100644 --- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts +++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts @@ -13,7 +13,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { const supertest = getService('supertest'); describe('saved objects security and spaces enabled', function () { - this.tags('ciGroup8'); + this.tags('ciGroup20'); before(async () => { await createUsersAndRoles(es, supertest); diff --git a/x-pack/test/saved_object_tagging/functional/tests/index.ts b/x-pack/test/saved_object_tagging/functional/tests/index.ts index 7a82574f34b6e..fbf0954382dd1 100644 --- a/x-pack/test/saved_object_tagging/functional/tests/index.ts +++ b/x-pack/test/saved_object_tagging/functional/tests/index.ts @@ -11,7 +11,7 @@ import { createUsersAndRoles } from '../../common/lib'; // eslint-disable-next-line import/no-default-export export default function ({ loadTestFile, getService }: FtrProviderContext) { describe('saved objects tagging - functional tests', function () { - this.tags('ciGroup2'); + this.tags('ciGroup14'); before(async () => { await createUsersAndRoles(getService); diff --git a/x-pack/test/security_api_integration/tests/kerberos/index.ts b/x-pack/test/security_api_integration/tests/kerberos/index.ts index 3faec0badd89e..39aac8cc4ca2f 100644 --- a/x-pack/test/security_api_integration/tests/kerberos/index.ts +++ b/x-pack/test/security_api_integration/tests/kerberos/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security APIs - Kerberos', function () { - this.tags('ciGroup6'); + this.tags('ciGroup16'); loadTestFile(require.resolve('./kerberos_login')); }); diff --git a/x-pack/test/security_api_integration/tests/saml/index.ts b/x-pack/test/security_api_integration/tests/saml/index.ts index 375864c71432d..dbabb835ee980 100644 --- a/x-pack/test/security_api_integration/tests/saml/index.ts +++ b/x-pack/test/security_api_integration/tests/saml/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security APIs - SAML', function () { - this.tags('ciGroup6'); + this.tags('ciGroup18'); loadTestFile(require.resolve('./saml_login')); }); diff --git a/x-pack/test/security_api_integration/tests/session_idle/index.ts b/x-pack/test/security_api_integration/tests/session_idle/index.ts index bbf811de70db4..76457ee7ad0c7 100644 --- a/x-pack/test/security_api_integration/tests/session_idle/index.ts +++ b/x-pack/test/security_api_integration/tests/session_idle/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('security APIs - Session Idle', function () { - this.tags('ciGroup6'); + this.tags('ciGroup18'); loadTestFile(require.resolve('./cleanup')); loadTestFile(require.resolve('./extension')); From 6b8145479502a22bbb9107666a84a146e7a35a1f Mon Sep 17 00:00:00 2001 From: ymao1 Date: Wed, 10 Nov 2021 12:10:43 -0500 Subject: [PATCH 08/51] Removing focusable element in tags badge (#118062) --- .../application/sections/alerts_list/components/alerts_list.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx index b48d5a6a3629f..162f41605e91e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx @@ -438,6 +438,7 @@ export const AlertsList: React.FunctionComponent = () => { color="hollow" iconType="tag" iconSide="left" + tabIndex={-1} onClick={() => setTagPopoverOpenIndex(item.index)} onClickAriaLabel="Tags" iconOnClick={() => setTagPopoverOpenIndex(item.index)} From 42168954b422149dece5f4b5e3244cfa552ec326 Mon Sep 17 00:00:00 2001 From: gchaps <33642766+gchaps@users.noreply.github.com> Date: Wed, 10 Nov 2021 10:20:23 -0800 Subject: [PATCH 09/51] [DOCS] Renames index pattern in management and monitoring (#117939) * [DOCS] Renames index pattern in management, monitoring, and graph * [DOCS] Renames index pattern on landing page * Updates URL in doc link service * Update docs/management/advanced-options.asciidoc Co-authored-by: Lisa Cawley * Update docs/user/monitoring/kibana-alerts.asciidoc Co-authored-by: Lisa Cawley Co-authored-by: lcawl Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- docs/index-extra-title-page.html | 2 +- docs/management/advanced-options.asciidoc | 18 ++--- .../management-rollup-index-pattern.png | Bin 59955 -> 0 bytes ...ns.asciidoc => manage-data-views.asciidoc} | 70 ++++++++++-------- .../managing-saved-objects.asciidoc | 8 +- docs/management/numeral.asciidoc | 2 +- .../create_and_manage_rollups.asciidoc | 28 +++---- docs/redirects.asciidoc | 5 ++ docs/user/graph/configuring-graph.asciidoc | 2 +- docs/user/management.asciidoc | 10 +-- docs/user/monitoring/kibana-alerts.asciidoc | 28 +++---- .../public/doc_links/doc_links_service.ts | 2 +- 12 files changed, 90 insertions(+), 85 deletions(-) delete mode 100644 docs/management/images/management-rollup-index-pattern.png rename docs/management/{manage-index-patterns.asciidoc => manage-data-views.asciidoc} (76%) diff --git a/docs/index-extra-title-page.html b/docs/index-extra-title-page.html index 2621848ebea8a..ff1c879c0f409 100644 --- a/docs/index-extra-title-page.html +++ b/docs/index-extra-title-page.html @@ -64,7 +64,7 @@
  • Create an index patternCreate a data view
  • diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 56b7eb09252ed..7e7ff1137794c 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -2,7 +2,7 @@ == Advanced Settings *Advanced Settings* control the behavior of {kib}. For example, you can change the format used to display dates, -specify the default index pattern, and set the precision for displayed decimal values. +specify the default data view, and set the precision for displayed decimal values. . Open the main menu, then click *Stack Management > Advanced Settings*. . Scroll or search for the setting. @@ -134,10 +134,6 @@ value by the maximum number of aggregations in each visualization. [[history-limit]]`history:limit`:: In fields that have history, such as query inputs, show this many recent values. -[[indexpattern-placeholder]]`indexPattern:placeholder`:: -The default placeholder value to use in -*Management > Index Patterns > Create Index Pattern*. - [[metafields]]`metaFields`:: Fields that exist outside of `_source`. Kibana merges these fields into the document when displaying it. @@ -283,7 +279,7 @@ value is 5. [[context-tiebreakerfields]]`context:tieBreakerFields`:: A comma-separated list of fields to use for breaking a tie between documents that have the same timestamp value. The first field that is present and sortable -in the current index pattern is used. +in the current data view is used. [[defaultcolumns]]`defaultColumns`:: The columns that appear by default on the *Discover* page. The default is @@ -296,7 +292,7 @@ The number of rows to show in the *Discover* table. Specifies the maximum number of fields to show in the document column of the *Discover* table. [[discover-modify-columns-on-switch]]`discover:modifyColumnsOnSwitch`:: -When enabled, removes the columns that are not in the new index pattern. +When enabled, removes the columns that are not in the new data view. [[discover-sample-size]]`discover:sampleSize`:: Specifies the number of rows to display in the *Discover* table. @@ -314,7 +310,7 @@ does not have an effect when loading a saved search. When enabled, displays multi-fields in the expanded document view. [[discover-sort-defaultorder]]`discover:sort:defaultOrder`:: -The default sort direction for time-based index patterns. +The default sort direction for time-based data views. [[doctable-hidetimecolumn]]`doc_table:hideTimeColumn`:: Hides the "Time" column in *Discover* and in all saved searches on dashboards. @@ -391,8 +387,8 @@ A custom image to use in the footer of the PDF. ==== Rollup [horizontal] -[[rollups-enableindexpatterns]]`rollups:enableIndexPatterns`:: -Enables the creation of index patterns that capture rollup indices, which in +[[rollups-enabledataviews]]`rollups:enableDataViews`:: +Enables the creation of data views that capture rollup indices, which in turn enables visualizations based on rollup data. Refresh the page to apply the changes. @@ -408,7 +404,7 @@ to use when `courier:setRequestPreference` is set to "custom". [[courier-ignorefilteriffieldnotinindex]]`courier:ignoreFilterIfFieldNotInIndex`:: Skips filters that apply to fields that don't exist in the index for a visualization. Useful when dashboards consist of visualizations from multiple -index patterns. +data views. [[courier-maxconcurrentshardrequests]]`courier:maxConcurrentShardRequests`:: Controls the {ref}/search-multi-search.html[max_concurrent_shard_requests] diff --git a/docs/management/images/management-rollup-index-pattern.png b/docs/management/images/management-rollup-index-pattern.png deleted file mode 100644 index de7976e63f0503cfb861604f2b05b9335b9924a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59955 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 Jp#*> and <>. +To add runtime fields to your data views, open the data view you want to change, +then define the field values by emitting a single value using +the {ref}/modules-scripting-painless.html[Painless scripting language]. +You can also add runtime fields in <> and <>. -. Open the main menu, then click *Stack Management > Index Patterns*. +. Open the main menu, then click *Stack Management > Data Views*. -. Select the index pattern you want to add the runtime field to, then click *Add field*. +. Select the data view that you want to add the runtime field to, then click *Add field*. . Enter the field *Name*, then select the *Type*. -. Select *Set custom label*, then enter the label you want to display where the index pattern is used, such as *Discover*. +. Select *Set custom label*, then enter the label you want to display where the data view is used, +such as *Discover*. -. Select *Set value*, then define the script. The script must match the *Type*, or the index pattern fails anywhere it is used. +. Select *Set value*, then define the script. The script must match the *Type*, or the data view fails anywhere it is used. . To help you define the script, use the *Preview*: @@ -46,7 +53,8 @@ To add runtime fields to your index patterns, open the index pattern you want to * To filter the fields list, enter the keyword in *Filter fields*. -* To pin frequently used fields to the top of the list, hover over the field, then click image:images/stackManagement-indexPatterns-pinRuntimeField-7.15.png[Icon to pin field to the top of the list]. +* To pin frequently used fields to the top of the list, hover over the field, +then click image:images/stackManagement-indexPatterns-pinRuntimeField-7.15.png[Icon to pin field to the top of the list]. . Click *Create field*. @@ -54,7 +62,7 @@ To add runtime fields to your index patterns, open the index pattern you want to [[runtime-field-examples]] ==== Runtime field examples -Try the runtime field examples on your own using the <> data index pattern. +Try the runtime field examples on your own using the <> data. [float] [[simple-hello-world-example]] @@ -110,7 +118,7 @@ if (source != null) { emit(source); return; } -else { +else { emit("None"); } ---- @@ -123,7 +131,7 @@ def source = doc['machine.os.keyword'].value; if (source != "") { emit(source); } -else { +else { emit("None"); } ---- @@ -132,15 +140,15 @@ else { [[manage-runtime-fields]] ==== Manage runtime fields -Edit the settings for runtime fields, or remove runtime fields from index patterns. +Edit the settings for runtime fields, or remove runtime fields from data views. -. Open the main menu, then click *Stack Management > Index Patterns*. +. Open the main menu, then click *Stack Management > Data Views*. -. Select the index pattern that contains the runtime field you want to manage, then open the runtime field edit options or delete the runtime field. +. Select the data view that contains the runtime field you want to manage, then open the runtime field edit options or delete the runtime field. [float] [[scripted-fields]] -=== Add scripted fields to index patterns +=== Add scripted fields to data views deprecated::[7.13,Use {ref}/runtime.html[runtime fields] instead of scripted fields. Runtime fields support Painless scripts and provide greater flexibility.] @@ -168,11 +176,11 @@ https://www.elastic.co/blog/using-painless-kibana-scripted-fields[Using Painless [[create-scripted-field]] ==== Create scripted fields -Create and add scripted fields to your index patterns. +Create and add scripted fields to your data views. -. Open the main menu, then click *Stack Management > Index Patterns*. +. Open the main menu, then click *Stack Management > Data Views*. -. Select the index pattern you want to add a scripted field to. +. Select the data view you want to add a scripted field to. . Select the *Scripted fields* tab, then click *Add scripted field*. @@ -186,9 +194,9 @@ For more information about scripted fields in {es}, refer to {ref}/modules-scrip [[update-scripted-field]] ==== Manage scripted fields -. Open the main menu, then click *Stack Management > Index Patterns*. +. Open the main menu, then click *Stack Management > Data Views*. -. Select the index pattern that contains the scripted field you want to manage. +. Select the data view that contains the scripted field you want to manage. . Select the *Scripted fields* tab, then open the scripted field edit options or delete the scripted field. @@ -202,9 +210,9 @@ exceptions when you view the dynamically generated data. {kib} uses the same field types as {es}, however, some {es} field types are unsupported in {kib}. To customize how {kib} displays data fields, use the formatting options. -. Open the main menu, then click *Stack Management > Index Patterns*. +. Open the main menu, then click *Stack Management > Data Views*. -. Click the index pattern that contains the field you want to change. +. Click the data view that contains the field you want to change. . Find the field, then open the edit options (image:management/index-patterns/images/edit_icon.png[Data field edit icon]). @@ -261,4 +269,4 @@ include::field-formatters/string-formatter.asciidoc[] include::field-formatters/duration-formatter.asciidoc[] -include::field-formatters/color-formatter.asciidoc[] \ No newline at end of file +include::field-formatters/color-formatter.asciidoc[] diff --git a/docs/management/managing-saved-objects.asciidoc b/docs/management/managing-saved-objects.asciidoc index 5b39c6ad1c4cd..b9859575051af 100644 --- a/docs/management/managing-saved-objects.asciidoc +++ b/docs/management/managing-saved-objects.asciidoc @@ -2,10 +2,10 @@ == Saved Objects The *Saved Objects* UI helps you keep track of and manage your saved objects. These objects -store data for later use, including dashboards, visualizations, maps, index patterns, +store data for later use, including dashboards, visualizations, maps, data views, Canvas workpads, and more. -To get started, open the main menu, then click *Stack Management > Saved Objects*. +To get started, open the main menu, then click *Stack Management > Saved Objects*. [role="screenshot"] image::images/management-saved-objects.png[Saved Objects] @@ -85,7 +85,7 @@ You have two options for exporting saved objects. * Click *Export x objects*, and export objects by type. This action creates an NDJSON with all your saved objects. By default, the NDJSON includes child objects that are related to the saved -objects. Exported dashboards include their associated index patterns. +objects. Exported dashboards include their associated data views. NOTE: The <> configuration setting limits the number of saved objects which may be exported. @@ -120,7 +120,7 @@ If you access an object whose index has been deleted, you can: * Recreate the index so you can continue using the object. * Delete the object and recreate it using a different index. * Change the index name in the object's `reference` array to point to an existing -index pattern. This is useful if the index you were working with has been renamed. +data view. This is useful if the index you were working with has been renamed. WARNING: Validation is not performed for object properties. Submitting an invalid change will render the object unusable. A more failsafe approach is to use diff --git a/docs/management/numeral.asciidoc b/docs/management/numeral.asciidoc index 893873eb1075a..d6c8fbc9011fc 100644 --- a/docs/management/numeral.asciidoc +++ b/docs/management/numeral.asciidoc @@ -9,7 +9,7 @@ they are now maintained by {kib}. Numeral formatting patterns are used in multiple places in {kib}, including: * <> -* <> +* <> * <> * <> diff --git a/docs/management/rollups/create_and_manage_rollups.asciidoc b/docs/management/rollups/create_and_manage_rollups.asciidoc index 51821a935d3f5..bdfd3f65b3c87 100644 --- a/docs/management/rollups/create_and_manage_rollups.asciidoc +++ b/docs/management/rollups/create_and_manage_rollups.asciidoc @@ -5,7 +5,7 @@ experimental::[] A rollup job is a periodic task that aggregates data from indices specified -by an index pattern, and then rolls it into a new index. Rollup indices are a good way to +by a data view, and then rolls it into a new index. Rollup indices are a good way to compactly store months or years of historical data for use in visualizations and reports. @@ -33,9 +33,9 @@ the process. You fill in the name, data flow, and how often you want to roll up the data. Then you define a date histogram aggregation for the rollup job and optionally define terms, histogram, and metrics aggregations. -When defining the index pattern, you must enter a name that is different than +When defining the data view, you must enter a name that is different than the output rollup index. Otherwise, the job -will attempt to capture the data in the rollup index. For example, if your index pattern is `metricbeat-*`, +will attempt to capture the data in the rollup index. For example, if your data view is `metricbeat-*`, you can name your rollup index `rollup-metricbeat`, but not `metricbeat-rollup`. [role="screenshot"] @@ -66,7 +66,7 @@ You can read more at {ref}/rollup-job-config.html[rollup job configuration]. This example creates a rollup job to capture log data from sample web logs. Before you start, <>. -In this example, you want data that is older than 7 days in the target index pattern `kibana_sample_data_logs` +In this example, you want data that is older than 7 days in the target data view `kibana_sample_data_logs` to roll up into the `rollup_logstash` index. You’ll bucket the rolled up data on an hourly basis, using 60m for the time bucket configuration. This allows for more granular queries, such as 2h and 12h. @@ -85,7 +85,7 @@ As you walk through the *Create rollup job* UI, enter the data: |Name |`logs_job` -|Index pattern +|Data view |`kibana_sample_data_logs` |Rollup index name @@ -139,27 +139,23 @@ rollup index, or you can remove or archive it using < Index Patterns*. +. Open the main menu, then click *Stack Management > Data Views*. -. Click *Create index pattern*, and select *Rollup index pattern* from the dropdown. -+ -[role="screenshot"] -image::images/management-rollup-index-pattern.png[][Create rollup index pattern] +. Click *Create data view*, and select *Rollup data view* from the dropdown. -. Enter *rollup_logstash,kibana_sample_logs* as your *Index Pattern* and `@timestamp` +. Enter *rollup_logstash,kibana_sample_logs* as your *Data View* and `@timestamp` as the *Time Filter field name*. + -The notation for a combination index pattern with both raw and rolled up data -is `rollup_logstash,kibana_sample_data_logs`. In this index pattern, `rollup_logstash` -matches the rolled up index pattern and `kibana_sample_data_logs` matches the index -pattern for raw data. +The notation for a combination data view with both raw and rolled up data +is `rollup_logstash,kibana_sample_data_logs`. In this data view, `rollup_logstash` +matches the rolled up data view and `kibana_sample_data_logs` matches the data view for raw data. . Open the main menu, click *Dashboard*, then *Create dashboard*. . Set the <> to *Last 90 days*. . On the dashboard, click *Create visualization*. - + . Choose `rollup_logstash,kibana_sample_data_logs` as your source to see both the raw and rolled up data. + diff --git a/docs/redirects.asciidoc b/docs/redirects.asciidoc index 4010083d601b5..2b00ccd67dc96 100644 --- a/docs/redirects.asciidoc +++ b/docs/redirects.asciidoc @@ -363,3 +363,8 @@ This content has moved. Refer to <>. == Index patterns has been renamed to data views. This content has moved. Refer to <>. + +[role="exclude",id="managing-index-patterns"] +== Index patterns has been renamed to data views. + +This content has moved. Refer to <>. diff --git a/docs/user/graph/configuring-graph.asciidoc b/docs/user/graph/configuring-graph.asciidoc index 968e08db33d49..aa9e6e6db3ee6 100644 --- a/docs/user/graph/configuring-graph.asciidoc +++ b/docs/user/graph/configuring-graph.asciidoc @@ -8,7 +8,7 @@ By default, both the configuration and data are saved for the workspace: [horizontal] *configuration*:: -The selected index pattern, fields, colors, icons, +The selected data view, fields, colors, icons, and settings. *data*:: The visualized content (the vertices and connections displayed in diff --git a/docs/user/management.asciidoc b/docs/user/management.asciidoc index 1f38d50e2d0bd..9d6392c39ba84 100644 --- a/docs/user/management.asciidoc +++ b/docs/user/management.asciidoc @@ -4,7 +4,7 @@ [partintro] -- *Stack Management* is home to UIs for managing all things Elastic Stack— -indices, clusters, licenses, UI settings, index patterns, spaces, and more. +indices, clusters, licenses, UI settings, data views, spaces, and more. Access to individual features is governed by {es} and {kib} privileges. @@ -128,12 +128,12 @@ Kerberos, PKI, OIDC, and SAML. [cols="50, 50"] |=== -a| <> -|Manage the data fields in the index patterns that retrieve your data from {es}. +a| <> +|Manage the fields in the data views that retrieve your data from {es}. | <> | Copy, edit, delete, import, and export your saved objects. -These include dashboards, visualizations, maps, index patterns, Canvas workpads, and more. +These include dashboards, visualizations, maps, data views, Canvas workpads, and more. | <> |Create, manage, and assign tags to your saved objects. @@ -183,7 +183,7 @@ include::{kib-repo-dir}/management/action-types.asciidoc[] include::{kib-repo-dir}/management/managing-licenses.asciidoc[] -include::{kib-repo-dir}/management/manage-index-patterns.asciidoc[] +include::{kib-repo-dir}/management/manage-data-views.asciidoc[] include::{kib-repo-dir}/management/numeral.asciidoc[] diff --git a/docs/user/monitoring/kibana-alerts.asciidoc b/docs/user/monitoring/kibana-alerts.asciidoc index 64ba8bf044e4f..f6deaed7fa3b9 100644 --- a/docs/user/monitoring/kibana-alerts.asciidoc +++ b/docs/user/monitoring/kibana-alerts.asciidoc @@ -5,21 +5,21 @@ The {stack} {monitor-features} provide <> out-of-the box to notify you of potential issues in the {stack}. These rules are preconfigured based on the -best practices recommended by Elastic. However, you can tailor them to meet your +best practices recommended by Elastic. However, you can tailor them to meet your specific needs. [role="screenshot"] image::user/monitoring/images/monitoring-kibana-alerting-notification.png["{kib} alerting notifications in {stack-monitor-app}"] -When you open *{stack-monitor-app}* for the first time, you will be asked to acknowledge the creation of these default rules. They are initially configured to detect and notify on various +When you open *{stack-monitor-app}* for the first time, you will be asked to acknowledge the creation of these default rules. They are initially configured to detect and notify on various conditions across your monitored clusters. You can view notifications for: *Cluster health*, *Resource utilization*, and *Errors and exceptions* for {es} in real time. -NOTE: The default {watcher} based "cluster alerts" for {stack-monitor-app} have -been recreated as rules in {kib} {alert-features}. For this reason, the existing -{watcher} email action +NOTE: The default {watcher} based "cluster alerts" for {stack-monitor-app} have +been recreated as rules in {kib} {alert-features}. For this reason, the existing +{watcher} email action `monitoring.cluster_alerts.email_notifications.email_address` no longer works. -The default action for all {stack-monitor-app} rules is to write to {kib} logs +The default action for all {stack-monitor-app} rules is to write to {kib} logs and display a notification in the UI. To review and modify existing *{stack-monitor-app}* rules, click *Enter setup mode* on the *Cluster overview* page. @@ -47,21 +47,21 @@ checks on a schedule time of 1 minute with a re-notify interval of 1 day. This rule checks for {es} nodes that use a high amount of JVM memory. By default, the condition is set at 85% or more averaged over the last 5 minutes. -The default rule checks on a schedule time of 1 minute with a re-notify interval of 1 day. +The default rule checks on a schedule time of 1 minute with a re-notify interval of 1 day. [discrete] [[kibana-alerts-missing-monitoring-data]] == Missing monitoring data -This rule checks for {es} nodes that stop sending monitoring data. By default, +This rule checks for {es} nodes that stop sending monitoring data. By default, the condition is set to missing for 15 minutes looking back 1 day. The default rule checks on a schedule -time of 1 minute with a re-notify interval of 6 hours. +time of 1 minute with a re-notify interval of 6 hours. [discrete] [[kibana-alerts-thread-pool-rejections]] == Thread pool rejections (search/write) -This rule checks for {es} nodes that experience thread pool rejections. By +This rule checks for {es} nodes that experience thread pool rejections. By default, the condition is set at 300 or more over the last 5 minutes. The default rule checks on a schedule time of 1 minute with a re-notify interval of 1 day. Thresholds can be set independently for `search` and `write` type rejections. @@ -72,14 +72,14 @@ independently for `search` and `write` type rejections. This rule checks for read exceptions on any of the replicated {es} clusters. The condition is met if 1 or more read exceptions are detected in the last hour. The -default rule checks on a schedule time of 1 minute with a re-notify interval of 6 hours. +default rule checks on a schedule time of 1 minute with a re-notify interval of 6 hours. [discrete] [[kibana-alerts-large-shard-size]] == Large shard size This rule checks for a large average shard size (across associated primaries) on -any of the specified index patterns in an {es} cluster. The condition is met if +any of the specified data views in an {es} cluster. The condition is met if an index's average shard size is 55gb or higher in the last 5 minutes. The default rule matches the pattern of `-.*` by running checks on a schedule time of 1 minute with a re-notify interval of 12 hours. @@ -124,8 +124,8 @@ valid for 30 days. == Alerts and rules [discrete] === Create default rules -This option can be used to create default rules in this kibana space. This is -useful for scenarios when you didn't choose to create these default rules initially +This option can be used to create default rules in this Kibana space. This is +useful for scenarios when you didn't choose to create these default rules initially or anytime later if the rules were accidentally deleted. NOTE: Some action types are subscription features, while others are free. diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index 6345f310d25da..41bf27c7706a9 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -158,7 +158,7 @@ export class DocLinksService { introduction: `${KIBANA_DOCS}index-patterns.html`, fieldFormattersNumber: `${KIBANA_DOCS}numeral.html`, fieldFormattersString: `${KIBANA_DOCS}field-formatters-string.html`, - runtimeFields: `${KIBANA_DOCS}managing-index-patterns.html#runtime-fields`, + runtimeFields: `${KIBANA_DOCS}managing-data-views.html#runtime-fields`, }, addData: `${KIBANA_DOCS}connect-to-elasticsearch.html`, kibana: `${KIBANA_DOCS}index.html`, From 252b949b61ace8ad9859407557918b73bb92b65c Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 10 Nov 2021 12:04:45 -0700 Subject: [PATCH 10/51] Remove direct usage of EUI theme vars (#116232) Co-authored-by: spalger Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../elastic-eslint-config-kibana/.eslintrc.js | 10 ++++++ packages/kbn-ui-shared-deps-npm/BUILD.bazel | 1 - .../eui_theme_vars/package.json | 4 --- packages/kbn-ui-shared-deps-src/src/index.js | 3 +- packages/kbn-ui-shared-deps-src/src/theme.ts | 2 ++ .../public/static/components/current_time.tsx | 6 ++-- .../public/static/components/endzones.tsx | 6 ++-- .../discover_grid_document_selection.tsx | 6 ++-- .../discover_grid_expand_button.tsx | 6 ++-- .../discover_grid/get_render_cell_value.tsx | 6 ++-- .../public/react_expression_renderer.tsx | 2 +- .../components/form_fields/type_field.tsx | 5 ++- .../public/code_editor/code_editor_field.tsx | 6 ++-- .../public/code_editor/editor_theme.ts | 6 ++-- .../vislib/components/tooltip/tooltip.js | 2 +- x-pack/plugins/apm/common/viz_colors.ts | 2 +- .../service_inventory.spec.ts | 3 +- .../plugins/apm/public/application/uxApp.tsx | 3 +- .../PercentileAnnotations.tsx | 2 +- .../URLFilter/URLSearch/render_option.tsx | 2 +- .../app/service_map/Controls.test.tsx | 2 +- .../public/components/routing/app_root.tsx | 3 +- .../apm/public/utils/httpStatusCodeToColor.ts | 2 +- .../java/gc/fetch_and_transform_gc_metrics.ts | 2 +- .../by_agent/java/gc/get_gc_rate_chart.ts | 2 +- .../by_agent/java/gc/get_gc_time_chart.ts | 2 +- .../by_agent/java/heap_memory/index.ts | 2 +- .../by_agent/java/non_heap_memory/index.ts | 2 +- .../by_agent/java/thread_count/index.ts | 2 +- .../lib/metrics/by_agent/shared/cpu/index.ts | 2 +- .../lib/metrics/transform_metrics_chart.ts | 2 +- .../public/common/mock/test_providers.tsx | 2 +- .../components/header_page/index.test.tsx | 2 +- .../utility_bar/utility_bar.test.tsx | 2 +- .../stats_table/hooks/use_color_range.ts | 6 ++-- .../agents/components/agent_health.tsx | 4 +-- .../sections/agents/services/agent_status.tsx | 6 ++-- .../ml/common/util/group_color_utils.ts | 2 +- .../color_range_legend/use_color_range.ts | 6 ++-- .../components/job_messages/job_messages.tsx | 2 +- .../scatterplot_matrix.test.tsx | 2 +- .../scatterplot_matrix_vega_lite_spec.test.ts | 2 +- .../scatterplot_matrix_vega_lite_spec.ts | 2 +- .../get_roc_curve_chart_vega_lite_spec.tsx | 2 +- .../decision_path_chart.tsx | 2 +- .../feature_importance_summary.tsx | 2 +- .../components/charts/common/settings.ts | 6 ++-- .../core_web_vitals/palette_legends.tsx | 3 +- x-pack/plugins/osquery/public/application.tsx | 3 +- .../__examples__/index.stories.tsx | 2 +- .../conditions_table/index.stories.tsx | 2 +- .../viewer/exception_item/index.stories.tsx | 2 +- .../exceptions_viewer_header.stories.tsx | 2 +- .../components/header_page/index.test.tsx | 2 +- .../components/header_section/index.test.tsx | 2 +- .../item_details_card/index.stories.tsx | 2 +- .../text_field_value/index.stories.tsx | 2 +- .../threat_match/logic_buttons.stories.tsx | 2 +- .../utility_bar/utility_bar.test.tsx | 2 +- .../public/common/lib/theme/use_eui_theme.tsx | 6 ++-- .../public/common/mock/test_providers.tsx | 2 +- .../components/rules/severity_badge/index.tsx | 2 +- .../components/rules/step_about_rule/data.tsx | 2 +- .../components/config_form/index.stories.tsx | 2 +- .../trusted_apps_grid/index.stories.tsx | 2 +- .../view_type_toggle/index.stories.tsx | 2 +- .../network/components/details/index.tsx | 6 ++-- .../map_tool_tip/tooltip_footer.tsx | 2 +- .../components/host_overview/index.tsx | 6 ++-- .../public/resolver/view/use_colors.ts | 36 +++++++++---------- .../public/resolver/view/use_cube_assets.ts | 20 +++++------ .../timelines/public/mock/test_providers.tsx | 2 +- .../expanded_row_messages_pane.tsx | 2 +- .../components/execution_duration_chart.tsx | 2 +- .../public/contexts/uptime_theme_context.tsx | 3 +- 75 files changed, 149 insertions(+), 130 deletions(-) delete mode 100644 packages/kbn-ui-shared-deps-npm/eui_theme_vars/package.json diff --git a/packages/elastic-eslint-config-kibana/.eslintrc.js b/packages/elastic-eslint-config-kibana/.eslintrc.js index 6bfefc8e118d4..99377540d38f7 100644 --- a/packages/elastic-eslint-config-kibana/.eslintrc.js +++ b/packages/elastic-eslint-config-kibana/.eslintrc.js @@ -88,6 +88,16 @@ module.exports = { exclude: USES_STYLED_COMPONENTS, disallowedMessage: `Prefer using @emotion/react instead. To use styled-components, ensure you plugin is enabled in @kbn/dev-utils/src/babel.ts.` }, + ...[ + '@elastic/eui/dist/eui_theme_light.json', + '@elastic/eui/dist/eui_theme_dark.json', + '@elastic/eui/dist/eui_theme_amsterdam_light.json', + '@elastic/eui/dist/eui_theme_amsterdam_dark.json', + ].map(from => ({ + from, + to: false, + disallowedMessage: `Use "@kbn/ui-shared-deps-src/theme" to access theme vars.` + })), ], ], diff --git a/packages/kbn-ui-shared-deps-npm/BUILD.bazel b/packages/kbn-ui-shared-deps-npm/BUILD.bazel index bbad873429b2b..416a4d4799b7b 100644 --- a/packages/kbn-ui-shared-deps-npm/BUILD.bazel +++ b/packages/kbn-ui-shared-deps-npm/BUILD.bazel @@ -23,7 +23,6 @@ filegroup( ) NPM_MODULE_EXTRA_FILES = [ - "eui_theme_vars/package.json", "package.json", "README.md" ] diff --git a/packages/kbn-ui-shared-deps-npm/eui_theme_vars/package.json b/packages/kbn-ui-shared-deps-npm/eui_theme_vars/package.json deleted file mode 100644 index a2448adf4d096..0000000000000 --- a/packages/kbn-ui-shared-deps-npm/eui_theme_vars/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "../target_node/eui_theme_vars.js", - "types": "../target_types/eui_theme_vars.d.ts" -} \ No newline at end of file diff --git a/packages/kbn-ui-shared-deps-src/src/index.js b/packages/kbn-ui-shared-deps-src/src/index.js index 3e3643d3e2988..630cf75c447fd 100644 --- a/packages/kbn-ui-shared-deps-src/src/index.js +++ b/packages/kbn-ui-shared-deps-src/src/index.js @@ -59,8 +59,7 @@ exports.externals = { '@elastic/eui/lib/services': '__kbnSharedDeps__.ElasticEuiLibServices', '@elastic/eui/lib/services/format': '__kbnSharedDeps__.ElasticEuiLibServicesFormat', '@elastic/eui/dist/eui_charts_theme': '__kbnSharedDeps__.ElasticEuiChartsTheme', - '@elastic/eui/dist/eui_theme_light.json': '__kbnSharedDeps__.Theme.euiLightVars', - '@elastic/eui/dist/eui_theme_dark.json': '__kbnSharedDeps__.Theme.euiDarkVars', + // transient dep of eui 'react-beautiful-dnd': '__kbnSharedDeps__.ReactBeautifulDnD', lodash: '__kbnSharedDeps__.Lodash', diff --git a/packages/kbn-ui-shared-deps-src/src/theme.ts b/packages/kbn-ui-shared-deps-src/src/theme.ts index f058913cdeeab..33b8a594bfa5d 100644 --- a/packages/kbn-ui-shared-deps-src/src/theme.ts +++ b/packages/kbn-ui-shared-deps-src/src/theme.ts @@ -6,7 +6,9 @@ * Side Public License, v 1. */ +/* eslint-disable-next-line @kbn/eslint/module_migration */ import { default as v8Light } from '@elastic/eui/dist/eui_theme_amsterdam_light.json'; +/* eslint-disable-next-line @kbn/eslint/module_migration */ import { default as v8Dark } from '@elastic/eui/dist/eui_theme_amsterdam_dark.json'; const globals: any = typeof window === 'undefined' ? {} : window; diff --git a/src/plugins/charts/public/static/components/current_time.tsx b/src/plugins/charts/public/static/components/current_time.tsx index 9cc261bf3ed86..ad05f451b607f 100644 --- a/src/plugins/charts/public/static/components/current_time.tsx +++ b/src/plugins/charts/public/static/components/current_time.tsx @@ -10,8 +10,10 @@ import moment, { Moment } from 'moment'; import React, { FC } from 'react'; import { LineAnnotation, AnnotationDomainType, LineAnnotationStyle } from '@elastic/charts'; -import lightEuiTheme from '@elastic/eui/dist/eui_theme_light.json'; -import darkEuiTheme from '@elastic/eui/dist/eui_theme_dark.json'; +import { + euiLightVars as lightEuiTheme, + euiDarkVars as darkEuiTheme, +} from '@kbn/ui-shared-deps-src/theme'; interface CurrentTimeProps { isDarkMode: boolean; diff --git a/src/plugins/charts/public/static/components/endzones.tsx b/src/plugins/charts/public/static/components/endzones.tsx index 85a020e54eb37..695b51c9702d2 100644 --- a/src/plugins/charts/public/static/components/endzones.tsx +++ b/src/plugins/charts/public/static/components/endzones.tsx @@ -17,8 +17,10 @@ import { } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer } from '@elastic/eui'; -import lightEuiTheme from '@elastic/eui/dist/eui_theme_light.json'; -import darkEuiTheme from '@elastic/eui/dist/eui_theme_dark.json'; +import { + euiLightVars as lightEuiTheme, + euiDarkVars as darkEuiTheme, +} from '@kbn/ui-shared-deps-src/theme'; interface EndzonesProps { isDarkMode: boolean; diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx index abf63d2fe76b0..b1fc8993375da 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx @@ -17,8 +17,10 @@ import { EuiDataGridCellValueElementProps, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import themeDark from '@elastic/eui/dist/eui_theme_dark.json'; -import themeLight from '@elastic/eui/dist/eui_theme_light.json'; +import { + euiLightVars as themeLight, + euiDarkVars as themeDark, +} from '@kbn/ui-shared-deps-src/theme'; import { ElasticSearchHit } from '../../services/doc_views/doc_views_types'; import { DiscoverGridContext } from './discover_grid_context'; diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx index 1a7080b9613d0..3453a535f98dd 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx @@ -8,8 +8,10 @@ import React, { useContext, useEffect } from 'react'; import { EuiButtonIcon, EuiDataGridCellValueElementProps, EuiToolTip } from '@elastic/eui'; -import themeDark from '@elastic/eui/dist/eui_theme_dark.json'; -import themeLight from '@elastic/eui/dist/eui_theme_light.json'; +import { + euiLightVars as themeLight, + euiDarkVars as themeDark, +} from '@kbn/ui-shared-deps-src/theme'; import { i18n } from '@kbn/i18n'; import { DiscoverGridContext } from './discover_grid_context'; import { EsHitRecord } from '../../application/types'; diff --git a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx index bf7aaac1a86a2..8fd5f73701932 100644 --- a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx +++ b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx @@ -7,8 +7,10 @@ */ import React, { Fragment, useContext, useEffect } from 'react'; -import themeLight from '@elastic/eui/dist/eui_theme_light.json'; -import themeDark from '@elastic/eui/dist/eui_theme_dark.json'; +import { + euiLightVars as themeLight, + euiDarkVars as themeDark, +} from '@kbn/ui-shared-deps-src/theme'; import type { IndexPattern } from 'src/plugins/data/common'; import { diff --git a/src/plugins/expressions/public/react_expression_renderer.tsx b/src/plugins/expressions/public/react_expression_renderer.tsx index 77b4402b22c06..b42ea3f3fd149 100644 --- a/src/plugins/expressions/public/react_expression_renderer.tsx +++ b/src/plugins/expressions/public/react_expression_renderer.tsx @@ -12,7 +12,7 @@ import { Observable, Subscription } from 'rxjs'; import { filter } from 'rxjs/operators'; import useShallowCompareEffect from 'react-use/lib/useShallowCompareEffect'; import { EuiLoadingChart, EuiProgress } from '@elastic/eui'; -import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; import { IExpressionLoaderParams, ExpressionRenderError, ExpressionRendererEvent } from './types'; import { ExpressionAstExpression, IInterpreterRenderHandlers } from '../common'; import { ExpressionLoader } from './loader'; diff --git a/src/plugins/index_pattern_editor/public/components/form_fields/type_field.tsx b/src/plugins/index_pattern_editor/public/components/form_fields/type_field.tsx index e8a48c5679879..0f4a040d1317b 100644 --- a/src/plugins/index_pattern_editor/public/components/form_fields/type_field.tsx +++ b/src/plugins/index_pattern_editor/public/components/form_fields/type_field.tsx @@ -8,8 +8,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -// @ts-ignore -import { euiColorAccent } from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import { FormattedMessage } from '@kbn/i18n/react'; import { @@ -54,7 +53,7 @@ const rollupSelectItem = ( defaultMessage="Rollup data view" />   - + diff --git a/src/plugins/kibana_react/public/code_editor/code_editor_field.tsx b/src/plugins/kibana_react/public/code_editor/code_editor_field.tsx index 0e6ab21159f15..85263b7006c16 100644 --- a/src/plugins/kibana_react/public/code_editor/code_editor_field.tsx +++ b/src/plugins/kibana_react/public/code_editor/code_editor_field.tsx @@ -7,8 +7,10 @@ */ import React from 'react'; -import darkTheme from '@elastic/eui/dist/eui_theme_dark.json'; -import lightTheme from '@elastic/eui/dist/eui_theme_light.json'; +import { + euiLightVars as lightTheme, + euiDarkVars as darkTheme, +} from '@kbn/ui-shared-deps-src/theme'; import { EuiFormControlLayout } from '@elastic/eui'; import { CodeEditor, Props } from './code_editor'; 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 0f362a28ea622..6c2727b123de8 100644 --- a/src/plugins/kibana_react/public/code_editor/editor_theme.ts +++ b/src/plugins/kibana_react/public/code_editor/editor_theme.ts @@ -8,8 +8,10 @@ import { monaco } from '@kbn/monaco'; -import darkTheme from '@elastic/eui/dist/eui_theme_dark.json'; -import lightTheme from '@elastic/eui/dist/eui_theme_light.json'; +import { + euiLightVars as lightTheme, + euiDarkVars as darkTheme, +} from '@kbn/ui-shared-deps-src/theme'; // NOTE: For talk around where this theme information will ultimately live, // please see this discuss issue: https://github.com/elastic/kibana/issues/43814 diff --git a/src/plugins/vis_types/vislib/public/vislib/components/tooltip/tooltip.js b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/tooltip.js index e2decb86c9032..1faebdf0ce89c 100644 --- a/src/plugins/vis_types/vislib/public/vislib/components/tooltip/tooltip.js +++ b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/tooltip.js @@ -12,7 +12,7 @@ import $ from 'jquery'; import { Binder } from '../../lib/binder'; import { positionTooltip } from './position_tooltip'; -import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; let allContents = []; diff --git a/x-pack/plugins/apm/common/viz_colors.ts b/x-pack/plugins/apm/common/viz_colors.ts index 20287f6e097bc..5b4946f346841 100644 --- a/x-pack/plugins/apm/common/viz_colors.ts +++ b/x-pack/plugins/apm/common/viz_colors.ts @@ -5,7 +5,7 @@ * 2.0. */ -import lightTheme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as lightTheme } from '@kbn/ui-shared-deps-src/theme'; function getVizColorsForTheme(theme = lightTheme) { return [ diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_inventory/service_inventory.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_inventory/service_inventory.spec.ts index f82510c86116b..1122e3c88a315 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_inventory/service_inventory.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_inventory/service_inventory.spec.ts @@ -93,7 +93,8 @@ describe('When navigating to the service inventory', () => { cy.wait(aliasNames); }); - it('when selecting a different time range and clicking the refresh button', () => { + // FAILING, @caue.marcondes will be fixing soon + it.skip('when selecting a different time range and clicking the refresh button', () => { cy.wait(aliasNames); cy.changeTimeRange('Last 30 days'); diff --git a/x-pack/plugins/apm/public/application/uxApp.tsx b/x-pack/plugins/apm/public/application/uxApp.tsx index 51ce192327043..cfb1a5c354c2d 100644 --- a/x-pack/plugins/apm/public/application/uxApp.tsx +++ b/x-pack/plugins/apm/public/application/uxApp.tsx @@ -5,8 +5,7 @@ * 2.0. */ -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; import { EuiErrorBoundary } from '@elastic/eui'; import { AppMountParameters, CoreStart } from 'kibana/public'; import React from 'react'; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx index ac713ad8dd8a8..35c6fb3c634cc 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx @@ -13,7 +13,7 @@ import { LineAnnotationStyle, Position, } from '@elastic/charts'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import { EuiToolTip } from '@elastic/eui'; interface Props { diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/render_option.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/render_option.tsx index f5f5a04353c50..4a4d8e9d3e191 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/render_option.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/render_option.tsx @@ -8,7 +8,7 @@ import React, { ReactNode } from 'react'; import { EuiHighlight, EuiSelectableOption } from '@elastic/eui'; import styled from 'styled-components'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; const StyledSpan = styled.span` color: ${euiLightVars.euiColorSecondaryText}; diff --git a/x-pack/plugins/apm/public/components/app/service_map/Controls.test.tsx b/x-pack/plugins/apm/public/components/app/service_map/Controls.test.tsx index 2ebd63badc41e..f2dd9cce8f27e 100644 --- a/x-pack/plugins/apm/public/components/app/service_map/Controls.test.tsx +++ b/x-pack/plugins/apm/public/components/app/service_map/Controls.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import lightTheme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as lightTheme } from '@kbn/ui-shared-deps-src/theme'; import { render } from '@testing-library/react'; import cytoscape from 'cytoscape'; import React, { ReactNode } from 'react'; diff --git a/x-pack/plugins/apm/public/components/routing/app_root.tsx b/x-pack/plugins/apm/public/components/routing/app_root.tsx index bc4119a3e835a..0e8e6732dc943 100644 --- a/x-pack/plugins/apm/public/components/routing/app_root.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root.tsx @@ -5,8 +5,7 @@ * 2.0. */ -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; import { RouteRenderer, RouterProvider } from '@kbn/typed-react-router-config'; import React from 'react'; import { Route } from 'react-router-dom'; diff --git a/x-pack/plugins/apm/public/utils/httpStatusCodeToColor.ts b/x-pack/plugins/apm/public/utils/httpStatusCodeToColor.ts index 345eb7aa3f635..1b44a90fe7bfc 100644 --- a/x-pack/plugins/apm/public/utils/httpStatusCodeToColor.ts +++ b/x-pack/plugins/apm/public/utils/httpStatusCodeToColor.ts @@ -5,7 +5,7 @@ * 2.0. */ -import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; const { euiColorDarkShade, euiColorWarning } = theme; export const errorColor = '#c23c2b'; diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts index fb66cb9649085..117b372d445d2 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts @@ -6,7 +6,7 @@ */ import { sum, round } from 'lodash'; -import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; import { isFiniteNumber } from '../../../../../../common/utils/is_finite_number'; import { Setup } from '../../../../helpers/setup_request'; import { getMetricsDateHistogramParams } from '../../../../helpers/metrics'; diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_rate_chart.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_rate_chart.ts index 07f02bb6f8fdc..22dcb3e0f08ff 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_rate_chart.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_rate_chart.ts @@ -5,7 +5,7 @@ * 2.0. */ -import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_GC_COUNT } from '../../../../../../common/elasticsearch_fieldnames'; import { Setup } from '../../../../helpers/setup_request'; diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_time_chart.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_time_chart.ts index 9f2fc2ba582f3..4b85ad94f6494 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_time_chart.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_time_chart.ts @@ -5,7 +5,7 @@ * 2.0. */ -import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_GC_TIME } from '../../../../../../common/elasticsearch_fieldnames'; import { Setup } from '../../../../helpers/setup_request'; diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts index 71f3973f51998..a872a3af76d7e 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_HEAP_MEMORY_MAX, diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts index 2ed70bf846dfa..9fa758cb4dbd8 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_NON_HEAP_MEMORY_MAX, diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts index e5e98fc418e5d..306666d27cd1c 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_THREAD_COUNT, diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts index e5042c8c80c70..0911081b20324 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; import { i18n } from '@kbn/i18n'; import { METRIC_SYSTEM_CPU_PERCENT, diff --git a/x-pack/plugins/apm/server/lib/metrics/transform_metrics_chart.ts b/x-pack/plugins/apm/server/lib/metrics/transform_metrics_chart.ts index f4829f2d5faa0..fea853af93b84 100644 --- a/x-pack/plugins/apm/server/lib/metrics/transform_metrics_chart.ts +++ b/x-pack/plugins/apm/server/lib/metrics/transform_metrics_chart.ts @@ -5,7 +5,7 @@ * 2.0. */ -import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; import { ESSearchResponse } from '../../../../../../src/core/types/elasticsearch'; import { getVizColorForIndex } from '../../../common/viz_colors'; import { GenericMetricsRequest } from './fetch_and_transform_metrics'; diff --git a/x-pack/plugins/cases/public/common/mock/test_providers.tsx b/x-pack/plugins/cases/public/common/mock/test_providers.tsx index b31e9e4e1b19d..8a4b66d38cc0f 100644 --- a/x-pack/plugins/cases/public/common/mock/test_providers.tsx +++ b/x-pack/plugins/cases/public/common/mock/test_providers.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; +import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; import { I18nProvider } from '@kbn/i18n/react'; import React from 'react'; import { BehaviorSubject } from 'rxjs'; diff --git a/x-pack/plugins/cases/public/components/header_page/index.test.tsx b/x-pack/plugins/cases/public/components/header_page/index.test.tsx index d84a6d9272def..55e5d0907c869 100644 --- a/x-pack/plugins/cases/public/components/header_page/index.test.tsx +++ b/x-pack/plugins/cases/public/components/header_page/index.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; +import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; import { shallow } from 'enzyme'; import React from 'react'; diff --git a/x-pack/plugins/cases/public/components/utility_bar/utility_bar.test.tsx b/x-pack/plugins/cases/public/components/utility_bar/utility_bar.test.tsx index 98af25a9af466..43ebd9bee3ca9 100644 --- a/x-pack/plugins/cases/public/components/utility_bar/utility_bar.test.tsx +++ b/x-pack/plugins/cases/public/components/utility_bar/utility_bar.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; +import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; import { mount, shallow } from 'enzyme'; import React from 'react'; import { TestProviders } from '../../common/mock'; diff --git a/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/hooks/use_color_range.ts b/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/hooks/use_color_range.ts index b1d26a5437b44..92a88f4d60670 100644 --- a/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/hooks/use_color_range.ts +++ b/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/hooks/use_color_range.ts @@ -7,8 +7,10 @@ import d3 from 'd3'; import { useMemo } from 'react'; -import euiThemeLight from '@elastic/eui/dist/eui_theme_light.json'; -import euiThemeDark from '@elastic/eui/dist/eui_theme_dark.json'; +import { + euiLightVars as euiThemeLight, + euiDarkVars as euiThemeDark, +} from '@kbn/ui-shared-deps-src/theme'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_health.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_health.tsx index fbac6ad74906d..701d68c0e29e3 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_health.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_health.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { FormattedMessage, FormattedRelative } from '@kbn/i18n/react'; import { EuiBadge, EuiToolTip } from '@elastic/eui'; -import * as euiVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as euiVars } from '@kbn/ui-shared-deps-src/theme'; import type { Agent } from '../../../types'; @@ -29,7 +29,7 @@ const Status = { ), Inactive: ( - + ), diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/agent_status.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/agent_status.tsx index 74e9879936d42..8eafcef0dc6de 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/agent_status.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/agent_status.tsx @@ -7,20 +7,20 @@ import { euiPaletteColorBlindBehindText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import * as euiVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import type { SimplifiedAgentStatus } from '../../../types'; const visColors = euiPaletteColorBlindBehindText(); const colorToHexMap = { // using variables as mentioned here https://elastic.github.io/eui/#/guidelines/getting-started - default: euiVars.default.euiColorLightShade, + default: euiLightVars.euiColorLightShade, primary: visColors[1], secondary: visColors[0], accent: visColors[2], warning: visColors[5], danger: visColors[9], - inactive: euiVars.default.euiColorDarkShade, + inactive: euiLightVars.euiColorDarkShade, }; export const AGENT_STATUSES: SimplifiedAgentStatus[] = [ diff --git a/x-pack/plugins/ml/common/util/group_color_utils.ts b/x-pack/plugins/ml/common/util/group_color_utils.ts index bb3b347e25334..63f0e13676d58 100644 --- a/x-pack/plugins/ml/common/util/group_color_utils.ts +++ b/x-pack/plugins/ml/common/util/group_color_utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import euiVars from '@elastic/eui/dist/eui_theme_dark.json'; +import { euiDarkVars as euiVars } from '@kbn/ui-shared-deps-src/theme'; import { stringHash } from './string_utils'; diff --git a/x-pack/plugins/ml/public/application/components/color_range_legend/use_color_range.ts b/x-pack/plugins/ml/public/application/components/color_range_legend/use_color_range.ts index 2809a4321e7bb..2ccc687d145d0 100644 --- a/x-pack/plugins/ml/public/application/components/color_range_legend/use_color_range.ts +++ b/x-pack/plugins/ml/public/application/components/color_range_legend/use_color_range.ts @@ -7,8 +7,10 @@ import d3 from 'd3'; import { useMemo } from 'react'; -import euiThemeLight from '@elastic/eui/dist/eui_theme_light.json'; -import euiThemeDark from '@elastic/eui/dist/eui_theme_dark.json'; +import { + euiLightVars as euiThemeLight, + euiDarkVars as euiThemeDark, +} from '@kbn/ui-shared-deps-src/theme'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/ml/public/application/components/job_messages/job_messages.tsx b/x-pack/plugins/ml/public/application/components/job_messages/job_messages.tsx index 2311807b6bbe6..facef2c02d578 100644 --- a/x-pack/plugins/ml/public/application/components/job_messages/job_messages.tsx +++ b/x-pack/plugins/ml/public/application/components/job_messages/job_messages.tsx @@ -17,7 +17,7 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; import { JobMessage } from '../../../../common/types/audit_message'; import { JobIcon } from '../job_message_icon'; diff --git a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.test.tsx b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.test.tsx index d0e70c38c23b4..846a8da83acb0 100644 --- a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.test.tsx +++ b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.test.tsx @@ -10,7 +10,7 @@ import { render, waitFor, screen } from '@testing-library/react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n/react'; -import euiThemeLight from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as euiThemeLight } from '@kbn/ui-shared-deps-src/theme'; import { ScatterplotMatrix } from './scatterplot_matrix'; diff --git a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.test.ts b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.test.ts index e401d70abe759..ed8a49cd36f02 100644 --- a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.test.ts +++ b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.test.ts @@ -10,7 +10,7 @@ import 'jest-canvas-mock'; // @ts-ignore import { compile } from 'vega-lite/build/vega-lite'; -import euiThemeLight from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as euiThemeLight } from '@kbn/ui-shared-deps-src/theme'; import { LEGEND_TYPES } from '../vega_chart/common'; diff --git a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.ts b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.ts index 861b3727cea1b..83525a4837dc9 100644 --- a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.ts +++ b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.ts @@ -9,7 +9,7 @@ // @ts-ignore import type { TopLevelSpec } from 'vega-lite/build/vega-lite'; -import euiThemeLight from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as euiThemeLight } from '@kbn/ui-shared-deps-src/theme'; import { euiPaletteColorBlind, euiPaletteNegative, euiPalettePositive } from '@elastic/eui'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/get_roc_curve_chart_vega_lite_spec.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/get_roc_curve_chart_vega_lite_spec.tsx index ef5bcb83e871f..2d116e0dd851e 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/get_roc_curve_chart_vega_lite_spec.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/get_roc_curve_chart_vega_lite_spec.tsx @@ -10,7 +10,7 @@ import type { TopLevelSpec } from 'vega-lite/build/vega-lite'; import { euiPaletteColorBlind, euiPaletteGray } from '@elastic/eui'; -import euiThemeLight from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as euiThemeLight } from '@kbn/ui-shared-deps-src/theme'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/feature_importance/decision_path_chart.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/feature_importance/decision_path_chart.tsx index dfaf58eba03d8..d91b742b8cfe1 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/feature_importance/decision_path_chart.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/feature_importance/decision_path_chart.tsx @@ -24,7 +24,7 @@ import { EuiIcon } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; -import euiVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as euiVars } from '@kbn/ui-shared-deps-src/theme'; import type { DecisionPathPlotData } from './use_classification_path_data'; import { formatSingleValue } from '../../../../../formatters/format_value'; import { diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/total_feature_importance_summary/feature_importance_summary.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/total_feature_importance_summary/feature_importance_summary.tsx index 6fe32a59c7614..9157e1fe4b678 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/total_feature_importance_summary/feature_importance_summary.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/total_feature_importance_summary/feature_importance_summary.tsx @@ -21,7 +21,7 @@ import { BarSeriesSpec, } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; -import euiVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as euiVars } from '@kbn/ui-shared-deps-src/theme'; import { TotalFeatureImportance, isClassificationTotalFeatureImportance, diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/common/settings.ts b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/common/settings.ts index 861b72a5a58b7..3d386073849f4 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/common/settings.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/common/settings.ts @@ -5,8 +5,10 @@ * 2.0. */ -import darkTheme from '@elastic/eui/dist/eui_theme_dark.json'; -import lightTheme from '@elastic/eui/dist/eui_theme_light.json'; +import { + euiLightVars as lightTheme, + euiDarkVars as darkTheme, +} from '@kbn/ui-shared-deps-src/theme'; import { JobCreatorType, isMultiMetricJobCreator, diff --git a/x-pack/plugins/observability/public/components/shared/core_web_vitals/palette_legends.tsx b/x-pack/plugins/observability/public/components/shared/core_web_vitals/palette_legends.tsx index 840702c744379..70ae61b5e0d74 100644 --- a/x-pack/plugins/observability/public/components/shared/core_web_vitals/palette_legends.tsx +++ b/x-pack/plugins/observability/public/components/shared/core_web_vitals/palette_legends.tsx @@ -16,8 +16,7 @@ import { } from '@elastic/eui'; import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n/react'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; +import { euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; import { getCoreVitalTooltipMessage, Thresholds } from './core_vital_item'; import { useUiSetting$ } from '../../../../../../../src/plugins/kibana_react/public'; import { diff --git a/x-pack/plugins/osquery/public/application.tsx b/x-pack/plugins/osquery/public/application.tsx index 3e959132e21a8..3e046a138cd4b 100644 --- a/x-pack/plugins/osquery/public/application.tsx +++ b/x-pack/plugins/osquery/public/application.tsx @@ -6,8 +6,7 @@ */ import { EuiErrorBoundary } from '@elastic/eui'; -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; import React, { useMemo } from 'react'; import ReactDOM from 'react-dom'; import { Router } from 'react-router-dom'; diff --git a/x-pack/plugins/security_solution/public/common/components/and_or_badge/__examples__/index.stories.tsx b/x-pack/plugins/security_solution/public/common/components/and_or_badge/__examples__/index.stories.tsx index 03a6a2653c1de..231f93e896df9 100644 --- a/x-pack/plugins/security_solution/public/common/components/and_or_badge/__examples__/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/and_or_badge/__examples__/index.stories.tsx @@ -8,7 +8,7 @@ import { storiesOf } from '@storybook/react'; import React, { ReactNode } from 'react'; import { ThemeProvider } from 'styled-components'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import { EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; import { AndOrBadge } from '..'; diff --git a/x-pack/plugins/security_solution/public/common/components/conditions_table/index.stories.tsx b/x-pack/plugins/security_solution/public/common/components/conditions_table/index.stories.tsx index 6fe0e6851a098..9efbbc7a3211d 100644 --- a/x-pack/plugins/security_solution/public/common/components/conditions_table/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/conditions_table/index.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { ThemeProvider } from 'styled-components'; import { storiesOf, addDecorator } from '@storybook/react'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import { createItems, TEST_COLUMNS } from './test_utils'; import { ConditionsTable } from '.'; diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.stories.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.stories.tsx index dd7f0f7a13e26..f8697b2f3db79 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.stories.tsx @@ -9,7 +9,7 @@ import { storiesOf, addDecorator } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import React from 'react'; import { ThemeProvider } from 'styled-components'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import { ExceptionItem } from './'; import { getExceptionListItemSchemaMock } from '../../../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exceptions_viewer_header.stories.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exceptions_viewer_header.stories.tsx index 4f78b49ea266c..de56e0eefc1ac 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exceptions_viewer_header.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exceptions_viewer_header.stories.tsx @@ -9,7 +9,7 @@ import { storiesOf, addDecorator } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import React from 'react'; import { ThemeProvider } from 'styled-components'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import { ExceptionsViewerHeader } from './exceptions_viewer_header'; diff --git a/x-pack/plugins/security_solution/public/common/components/header_page/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/header_page/index.test.tsx index 47b0871229864..2e25a357e86b1 100644 --- a/x-pack/plugins/security_solution/public/common/components/header_page/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/header_page/index.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; +import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; import { shallow } from 'enzyme'; import React from 'react'; diff --git a/x-pack/plugins/security_solution/public/common/components/header_section/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/header_section/index.test.tsx index cc0ac3e6c2b0c..07a5ad475aed2 100644 --- a/x-pack/plugins/security_solution/public/common/components/header_section/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/header_section/index.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; +import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; import { mount, shallow } from 'enzyme'; import React from 'react'; diff --git a/x-pack/plugins/security_solution/public/common/components/item_details_card/index.stories.tsx b/x-pack/plugins/security_solution/public/common/components/item_details_card/index.stories.tsx index d910d258e7bfe..513ba8ccdc462 100644 --- a/x-pack/plugins/security_solution/public/common/components/item_details_card/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/item_details_card/index.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { ThemeProvider } from 'styled-components'; import { storiesOf, addDecorator } from '@storybook/react'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import { ItemDetailsAction, ItemDetailsCard, ItemDetailsPropertySummary } from '.'; diff --git a/x-pack/plugins/security_solution/public/common/components/text_field_value/index.stories.tsx b/x-pack/plugins/security_solution/public/common/components/text_field_value/index.stories.tsx index b3f0de1376396..146ba8ef82505 100644 --- a/x-pack/plugins/security_solution/public/common/components/text_field_value/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/text_field_value/index.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { ThemeProvider } from 'styled-components'; import { storiesOf, addDecorator } from '@storybook/react'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import { TextFieldValue } from '.'; diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.stories.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.stories.tsx index 20a7786f6d09e..6497875ac8d4a 100644 --- a/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.stories.tsx @@ -9,7 +9,7 @@ import { storiesOf, addDecorator } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import React from 'react'; import { ThemeProvider } from 'styled-components'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import { LogicButtons } from './logic_buttons'; diff --git a/x-pack/plugins/security_solution/public/common/components/utility_bar/utility_bar.test.tsx b/x-pack/plugins/security_solution/public/common/components/utility_bar/utility_bar.test.tsx index 7a9413a92843e..73acaa48983b4 100644 --- a/x-pack/plugins/security_solution/public/common/components/utility_bar/utility_bar.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/utility_bar/utility_bar.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; +import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; import { mount, shallow } from 'enzyme'; import React from 'react'; diff --git a/x-pack/plugins/security_solution/public/common/lib/theme/use_eui_theme.tsx b/x-pack/plugins/security_solution/public/common/lib/theme/use_eui_theme.tsx index e9b66728b9a1d..0057666ba4262 100644 --- a/x-pack/plugins/security_solution/public/common/lib/theme/use_eui_theme.tsx +++ b/x-pack/plugins/security_solution/public/common/lib/theme/use_eui_theme.tsx @@ -5,8 +5,10 @@ * 2.0. */ -import darkTheme from '@elastic/eui/dist/eui_theme_dark.json'; -import lightTheme from '@elastic/eui/dist/eui_theme_light.json'; +import { + euiLightVars as lightTheme, + euiDarkVars as darkTheme, +} from '@kbn/ui-shared-deps-src/theme'; import { DEFAULT_DARK_MODE } from '../../../../common/constants'; import { useUiSetting$ } from '../kibana'; diff --git a/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx b/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx index 7ea93bb7ce8fb..f180dd2baf5f4 100644 --- a/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; +import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; import { I18nProvider } from '@kbn/i18n/react'; import React from 'react'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/severity_badge/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/severity_badge/index.tsx index 32075c48c7ff3..728e0ec871e93 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/severity_badge/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/severity_badge/index.tsx @@ -8,7 +8,7 @@ import { upperFirst } from 'lodash/fp'; import React from 'react'; import { EuiHealth } from '@elastic/eui'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; interface Props { value: string; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/data.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/data.tsx index 264e499d9cf86..df50946f058ba 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/data.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/data.tsx @@ -7,7 +7,7 @@ import styled from 'styled-components'; import { EuiHealth } from '@elastic/eui'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import React from 'react'; import { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/components/config_form/index.stories.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/components/config_form/index.stories.tsx index 796ecc30f4033..09321244e0abc 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/components/config_form/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/components/config_form/index.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { ThemeProvider } from 'styled-components'; import { addDecorator, storiesOf } from '@storybook/react'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import { EuiCheckbox, EuiSpacer, EuiSwitch, EuiText } from '@elastic/eui'; import { OperatingSystem } from '../../../../../../../common/endpoint/types'; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.stories.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.stories.tsx index 75323f8b55174..ecc18d5d52fd9 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.stories.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { Provider } from 'react-redux'; import { ThemeProvider } from 'styled-components'; import { storiesOf } from '@storybook/react'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import { EuiHorizontalRule } from '@elastic/eui'; import { KibanaContextProvider } from '../../../../../../../../../../src/plugins/kibana_react/public'; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/view_type_toggle/index.stories.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/view_type_toggle/index.stories.tsx index b8f98ebcf78bb..484f17318f839 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/view_type_toggle/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/view_type_toggle/index.stories.tsx @@ -8,7 +8,7 @@ import React, { useState } from 'react'; import { ThemeProvider } from 'styled-components'; import { storiesOf, addDecorator } from '@storybook/react'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import { ViewType } from '../../../state'; import { ViewTypeToggle } from '.'; diff --git a/x-pack/plugins/security_solution/public/network/components/details/index.tsx b/x-pack/plugins/security_solution/public/network/components/details/index.tsx index 0b53a4bfb3fe2..5cd2f4dfd72c8 100644 --- a/x-pack/plugins/security_solution/public/network/components/details/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/details/index.tsx @@ -5,8 +5,10 @@ * 2.0. */ -import darkTheme from '@elastic/eui/dist/eui_theme_dark.json'; -import lightTheme from '@elastic/eui/dist/eui_theme_light.json'; +import { + euiLightVars as lightTheme, + euiDarkVars as darkTheme, +} from '@kbn/ui-shared-deps-src/theme'; import React from 'react'; import { DEFAULT_DARK_MODE } from '../../../../common/constants'; diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/tooltip_footer.tsx b/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/tooltip_footer.tsx index dbb280228e504..a557ee7b8b190 100644 --- a/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/tooltip_footer.tsx +++ b/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/tooltip_footer.tsx @@ -14,7 +14,7 @@ import { EuiIcon, EuiText, } from '@elastic/eui'; -import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; import styled from 'styled-components'; import * as i18n from '../translations'; diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx index e73096aa3babf..0708892affe13 100644 --- a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx @@ -6,8 +6,10 @@ */ import { EuiHorizontalRule } from '@elastic/eui'; -import darkTheme from '@elastic/eui/dist/eui_theme_dark.json'; -import lightTheme from '@elastic/eui/dist/eui_theme_light.json'; +import { + euiLightVars as lightTheme, + euiDarkVars as darkTheme, +} from '@kbn/ui-shared-deps-src/theme'; import { getOr } from 'lodash/fp'; import React, { useCallback, useMemo } from 'react'; diff --git a/x-pack/plugins/security_solution/public/resolver/view/use_colors.ts b/x-pack/plugins/security_solution/public/resolver/view/use_colors.ts index baf3eff8b391c..f52075cbe4d85 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/use_colors.ts +++ b/x-pack/plugins/security_solution/public/resolver/view/use_colors.ts @@ -5,10 +5,8 @@ * 2.0. */ -import euiThemeAmsterdamDark from '@elastic/eui/dist/eui_theme_amsterdam_dark.json'; -import euiThemeAmsterdamLight from '@elastic/eui/dist/eui_theme_amsterdam_light.json'; +import { darkMode, euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; import { useMemo } from 'react'; -import { useUiSetting } from '../../../../../../src/plugins/kibana_react/public'; type ResolverColorNames = | 'copyableFieldBackground' @@ -31,24 +29,22 @@ type ColorMap = Record; * Get access to Kibana-theme based colors. */ export function useColors(): ColorMap { - const isDarkMode = useUiSetting('theme:darkMode'); - const theme = isDarkMode ? euiThemeAmsterdamDark : euiThemeAmsterdamLight; return useMemo(() => { return { - copyableFieldBackground: theme.euiColorLightShade, - descriptionText: theme.euiTextColor, - full: theme.euiColorFullShade, - graphControls: theme.euiColorDarkestShade, - graphControlsBackground: theme.euiColorEmptyShade, - graphControlsBorderColor: theme.euiColorLightShade, - processBackingFill: `${theme.euiColorPrimary}${isDarkMode ? '1F' : '0F'}`, // Add opacity 0F = 6% , 1F = 12% - resolverBackground: theme.euiColorEmptyShade, - resolverEdge: isDarkMode ? theme.euiColorLightShade : theme.euiColorLightestShade, - resolverBreadcrumbBackground: theme.euiColorLightestShade, - resolverEdgeText: isDarkMode ? theme.euiColorFullShade : theme.euiColorDarkShade, - triggerBackingFill: `${theme.euiColorDanger}${isDarkMode ? '1F' : '0F'}`, - pillStroke: theme.euiColorLightShade, - linkColor: theme.euiLinkColor, + copyableFieldBackground: euiThemeVars.euiColorLightShade, + descriptionText: euiThemeVars.euiTextColor, + full: euiThemeVars.euiColorFullShade, + graphControls: euiThemeVars.euiColorDarkestShade, + graphControlsBackground: euiThemeVars.euiColorEmptyShade, + graphControlsBorderColor: euiThemeVars.euiColorLightShade, + processBackingFill: `${euiThemeVars.euiColorPrimary}${darkMode ? '1F' : '0F'}`, // Add opacity 0F = 6% , 1F = 12% + resolverBackground: euiThemeVars.euiColorEmptyShade, + resolverEdge: darkMode ? euiThemeVars.euiColorLightShade : euiThemeVars.euiColorLightestShade, + resolverBreadcrumbBackground: euiThemeVars.euiColorLightestShade, + resolverEdgeText: darkMode ? euiThemeVars.euiColorFullShade : euiThemeVars.euiColorDarkShade, + triggerBackingFill: `${euiThemeVars.euiColorDanger}${darkMode ? '1F' : '0F'}`, + pillStroke: euiThemeVars.euiColorLightShade, + linkColor: euiThemeVars.euiLinkColor, }; - }, [isDarkMode, theme]); + }, []); } diff --git a/x-pack/plugins/security_solution/public/resolver/view/use_cube_assets.ts b/x-pack/plugins/security_solution/public/resolver/view/use_cube_assets.ts index 774c5f0ce1c74..f5a9c37623c47 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/use_cube_assets.ts +++ b/x-pack/plugins/security_solution/public/resolver/view/use_cube_assets.ts @@ -7,12 +7,10 @@ import { i18n } from '@kbn/i18n'; +import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; import { ButtonColor } from '@elastic/eui'; -import euiThemeAmsterdamDark from '@elastic/eui/dist/eui_theme_amsterdam_dark.json'; -import euiThemeAmsterdamLight from '@elastic/eui/dist/eui_theme_amsterdam_light.json'; import { useMemo } from 'react'; import { ResolverProcessType, NodeDataStatus } from '../types'; -import { useUiSetting } from '../../../../../../src/plugins/kibana_react/public'; import { useSymbolIDs } from './use_symbol_ids'; import { useColors } from './use_colors'; @@ -24,8 +22,6 @@ export function useCubeAssets( isProcessTrigger: boolean ): NodeStyleConfig { const SymbolIds = useSymbolIDs(); - const isDarkMode = useUiSetting('theme:darkMode'); - const theme = isDarkMode ? euiThemeAmsterdamDark : euiThemeAmsterdamLight; const colorMap = useColors(); const nodeAssets: NodeStyleMap = useMemo( @@ -39,7 +35,7 @@ export function useCubeAssets( }), isLabelFilled: true, labelButtonFill: 'primary', - strokeColor: theme.euiColorPrimary, + strokeColor: euiThemeVars.euiColorPrimary, }, loadingCube: { backingFill: colorMap.processBackingFill, @@ -50,7 +46,7 @@ export function useCubeAssets( }), isLabelFilled: false, labelButtonFill: 'primary', - strokeColor: theme.euiColorPrimary, + strokeColor: euiThemeVars.euiColorPrimary, }, errorCube: { backingFill: colorMap.processBackingFill, @@ -61,7 +57,7 @@ export function useCubeAssets( }), isLabelFilled: false, labelButtonFill: 'primary', - strokeColor: theme.euiColorPrimary, + strokeColor: euiThemeVars.euiColorPrimary, }, runningTriggerCube: { backingFill: colorMap.triggerBackingFill, @@ -72,7 +68,7 @@ export function useCubeAssets( }), isLabelFilled: true, labelButtonFill: 'danger', - strokeColor: theme.euiColorDanger, + strokeColor: euiThemeVars.euiColorDanger, }, terminatedProcessCube: { backingFill: colorMap.processBackingFill, @@ -86,7 +82,7 @@ export function useCubeAssets( ), isLabelFilled: false, labelButtonFill: 'primary', - strokeColor: theme.euiColorPrimary, + strokeColor: euiThemeVars.euiColorPrimary, }, terminatedTriggerCube: { backingFill: colorMap.triggerBackingFill, @@ -100,10 +96,10 @@ export function useCubeAssets( ), isLabelFilled: false, labelButtonFill: 'danger', - strokeColor: theme.euiColorDanger, + strokeColor: euiThemeVars.euiColorDanger, }, }), - [SymbolIds, colorMap, theme] + [SymbolIds, colorMap] ); if (cubeType === 'terminated') { diff --git a/x-pack/plugins/timelines/public/mock/test_providers.tsx b/x-pack/plugins/timelines/public/mock/test_providers.tsx index 9fa6177cccee1..0fb1afec43627 100644 --- a/x-pack/plugins/timelines/public/mock/test_providers.tsx +++ b/x-pack/plugins/timelines/public/mock/test_providers.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; +import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; import { I18nProvider } from '@kbn/i18n/react'; import React from 'react'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx index fc95b818126bc..3f8b0549c219b 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx @@ -10,7 +10,7 @@ import React, { useState } from 'react'; import { EuiSpacer, EuiBasicTable } from '@elastic/eui'; // @ts-ignore import { formatDate } from '@elastic/eui/lib/services/format'; -import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.tsx index ea8c16d03cc04..6b5a7ee3b3e4d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.tsx @@ -16,7 +16,7 @@ import { EuiIconTip, EuiTitle, } from '@elastic/eui'; -import lightEuiTheme from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars as lightEuiTheme } from '@kbn/ui-shared-deps-src/theme'; import { Axis, BarSeries, Chart, CurveType, LineSeries, Settings } from '@elastic/charts'; import { assign, fill } from 'lodash'; import { formatMillisForDisplay } from '../../../lib/execution_duration_utils'; diff --git a/x-pack/plugins/uptime/public/contexts/uptime_theme_context.tsx b/x-pack/plugins/uptime/public/contexts/uptime_theme_context.tsx index 7798aabc879a6..6df3879ef7407 100644 --- a/x-pack/plugins/uptime/public/contexts/uptime_theme_context.tsx +++ b/x-pack/plugins/uptime/public/contexts/uptime_theme_context.tsx @@ -5,9 +5,8 @@ * 2.0. */ -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; import React, { createContext, useMemo } from 'react'; -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; import { EUI_CHARTS_THEME_DARK, EUI_CHARTS_THEME_LIGHT } from '@elastic/eui/dist/eui_charts_theme'; import { DARK_THEME, LIGHT_THEME, PartialTheme, Theme } from '@elastic/charts'; import { UptimeAppColors } from '../apps/uptime_app'; From b389cfe0ab313ab5d8ae3724fc5dd94e3442c905 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 10 Nov 2021 20:23:25 +0100 Subject: [PATCH 11/51] fix addd to case relative (#117487) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/action_menu/action_menu.tsx | 8 ++++-- .../header/add_to_case_action.test.tsx | 28 +++++++++++++++++++ .../header/add_to_case_action.tsx | 8 ++++-- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/action_menu/action_menu.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/action_menu/action_menu.tsx index 08b4a3b948c57..512a6389bbf72 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/action_menu/action_menu.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/action_menu/action_menu.tsx @@ -36,9 +36,11 @@ export function ExpViewActionMenuContent({ responsive={false} style={{ paddingRight: 20 }} > - - - + {timeRange && ( + + + + )} + ); + expect(await findByText('Add to case')).toBeInTheDocument(); + + expect(useAddToCaseHook).toHaveBeenCalledWith( + expect.objectContaining({ + lensAttributes: { + title: 'Performance distribution', + }, + timeRange: { + from: '2021-11-10T10:52:06.091Z', + to: '2021-11-10T10:52:06.091Z', + }, + }) + ); + }); + it('should be able to click add to case button', async function () { const initSeries = { data: [ diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/header/add_to_case_action.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/header/add_to_case_action.tsx index bc813a4980e78..1d230c765edae 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/header/add_to_case_action.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/header/add_to_case_action.tsx @@ -15,9 +15,10 @@ import { TypedLensByValueInput } from '../../../../../../lens/public'; import { useAddToCase } from '../hooks/use_add_to_case'; import { Case, SubCase } from '../../../../../../cases/common'; import { observabilityFeatureId } from '../../../../../common'; +import { parseRelativeDate } from '../components/date_range_picker'; export interface AddToCaseProps { - timeRange?: { from: string; to: string }; + timeRange: { from: string; to: string }; lensAttributes: TypedLensByValueInput['attributes'] | null; } @@ -31,11 +32,14 @@ export function AddToCaseAction({ lensAttributes, timeRange }: AddToCaseProps) { [http.basePath] ); + const absoluteFromDate = parseRelativeDate(timeRange.from); + const absoluteToDate = parseRelativeDate(timeRange.to, { roundUp: true }); + const { createCaseUrl, goToCreateCase, onCaseClicked, isCasesOpen, setIsCasesOpen, isSaving } = useAddToCase({ lensAttributes, getToastText, - timeRange, + timeRange: { from: absoluteFromDate.toISOString(), to: absoluteToDate.toISOString() }, }); const getAllCasesSelectorModalProps: AllCasesSelectorModalProps = { From 75bafde7605f8cbb3f1dc5d462f6fc40afd0c312 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Wed, 10 Nov 2021 14:55:16 -0500 Subject: [PATCH 12/51] [Fleet] Remove force flag from agent instruction (#118099) --- .../components/install_command_utils.test.ts | 57 +++++++++---------- .../components/install_command_utils.ts | 6 +- .../enrollment_instructions/manual/index.tsx | 4 +- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/install_command_utils.test.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/install_command_utils.test.ts index b4e7982c52f7b..62580a1445f06 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/install_command_utils.test.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/install_command_utils.test.ts @@ -17,9 +17,9 @@ describe('getInstallCommandForPlatform', () => { ); expect(res).toMatchInlineSnapshot(` - "sudo ./elastic-agent install -f \\\\ - --fleet-server-es=http://elasticsearch:9200 \\\\ - --fleet-server-service-token=service-token-1" + "sudo ./elastic-agent install \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1" `); }); @@ -31,9 +31,9 @@ describe('getInstallCommandForPlatform', () => { ); expect(res).toMatchInlineSnapshot(` - ".\\\\elastic-agent.exe install -f \` - --fleet-server-es=http://elasticsearch:9200 \` - --fleet-server-service-token=service-token-1" + ".\\\\elastic-agent.exe install \` + --fleet-server-es=http://elasticsearch:9200 \` + --fleet-server-service-token=service-token-1" `); }); @@ -45,9 +45,9 @@ describe('getInstallCommandForPlatform', () => { ); expect(res).toMatchInlineSnapshot(` - "sudo elastic-agent enroll -f \\\\ - --fleet-server-es=http://elasticsearch:9200 \\\\ - --fleet-server-service-token=service-token-1" + "sudo elastic-agent enroll \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1" `); }); }); @@ -62,9 +62,9 @@ describe('getInstallCommandForPlatform', () => { ); expect(res).toMatchInlineSnapshot(` - "sudo ./elastic-agent install -f \\\\ - --fleet-server-es=http://elasticsearch:9200 \\\\ - --fleet-server-service-token=service-token-1 \\\\ + "sudo ./elastic-agent install \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1 \\\\ --fleet-server-policy=policy-1" `); }); @@ -78,9 +78,9 @@ describe('getInstallCommandForPlatform', () => { ); expect(res).toMatchInlineSnapshot(` - ".\\\\elastic-agent.exe install -f \` - --fleet-server-es=http://elasticsearch:9200 \` - --fleet-server-service-token=service-token-1 \` + ".\\\\elastic-agent.exe install \` + --fleet-server-es=http://elasticsearch:9200 \` + --fleet-server-service-token=service-token-1 \` --fleet-server-policy=policy-1" `); }); @@ -94,9 +94,9 @@ describe('getInstallCommandForPlatform', () => { ); expect(res).toMatchInlineSnapshot(` - "sudo elastic-agent enroll -f \\\\ - --fleet-server-es=http://elasticsearch:9200 \\\\ - --fleet-server-service-token=service-token-1 \\\\ + "sudo elastic-agent enroll \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1 \\\\ --fleet-server-policy=policy-1" `); }); @@ -115,9 +115,8 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "sudo ./elastic-agent install --url=http://fleetserver:8220 \\\\ - -f \\\\ - --fleet-server-es=http://elasticsearch:9200 \\\\ - --fleet-server-service-token=service-token-1 \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1 \\\\ --fleet-server-policy=policy-1 \\\\ --certificate-authorities= \\\\ --fleet-server-es-ca= \\\\ @@ -138,9 +137,8 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` ".\\\\elastic-agent.exe install --url=http://fleetserver:8220 \` - -f \` - --fleet-server-es=http://elasticsearch:9200 \` - --fleet-server-service-token=service-token-1 \` + --fleet-server-es=http://elasticsearch:9200 \` + --fleet-server-service-token=service-token-1 \` --fleet-server-policy=policy-1 \` --certificate-authorities= \` --fleet-server-es-ca= \` @@ -161,9 +159,8 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "sudo elastic-agent enroll --url=http://fleetserver:8220 \\\\ - -f \\\\ - --fleet-server-es=http://elasticsearch:9200 \\\\ - --fleet-server-service-token=service-token-1 \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1 \\\\ --fleet-server-policy=policy-1 \\\\ --certificate-authorities= \\\\ --fleet-server-es-ca= \\\\ @@ -181,9 +178,9 @@ describe('getInstallCommandForPlatform', () => { ); expect(res).toMatchInlineSnapshot(` - "sudo elastic-agent enroll -f \\\\ - --fleet-server-es=http://elasticsearch:9200 \\\\ - --fleet-server-service-token=service-token-1" + "sudo elastic-agent enroll \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1" `); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/install_command_utils.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/install_command_utils.ts index e129d7a4d5b4e..f5c40e8071691 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/install_command_utils.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/install_command_utils.ts @@ -20,10 +20,12 @@ export function getInstallCommandForPlatform( if (isProductionDeployment && fleetServerHost) { commandArguments += `--url=${fleetServerHost} ${newLineSeparator}\n`; + } else { + commandArguments += ` ${newLineSeparator}\n`; } - commandArguments += ` -f ${newLineSeparator}\n --fleet-server-es=${esHost}`; - commandArguments += ` ${newLineSeparator}\n --fleet-server-service-token=${serviceToken}`; + commandArguments += ` --fleet-server-es=${esHost}`; + commandArguments += ` ${newLineSeparator}\n --fleet-server-service-token=${serviceToken}`; if (policyId) { commandArguments += ` ${newLineSeparator}\n --fleet-server-policy=${policyId}`; } diff --git a/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx b/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx index 6d4d6a7172534..425fe6c6bd67e 100644 --- a/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx +++ b/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx @@ -38,9 +38,9 @@ export const ManualInstructions: React.FunctionComponent = ({ const enrollArgs = getfleetServerHostsEnrollArgs(apiKey, fleetServerHosts); - const linuxMacCommand = `sudo ./elastic-agent install -f ${enrollArgs}`; + const linuxMacCommand = `sudo ./elastic-agent install ${enrollArgs}`; - const windowsCommand = `.\\elastic-agent.exe install -f ${enrollArgs}`; + const windowsCommand = `.\\elastic-agent.exe install ${enrollArgs}`; return ( <> From 05246c67a02a3599d08ccad2a0e72f0623fb3c28 Mon Sep 17 00:00:00 2001 From: Claudio Procida Date: Wed, 10 Nov 2021 20:56:10 +0100 Subject: [PATCH 13/51] chore: rename test subjects to camel case (#118046) * chore: rename test subjects to camel case * chore: rename test subjects to camel case /2 * Updates expectations * Restores files not in observability * Fixes test subjects * Fixes selector * Fixes selector Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../app/cases/callout/callout.test.tsx | 22 ++++++++--------- .../components/app/cases/callout/callout.tsx | 6 ++--- .../app/cases/callout/index.test.tsx | 24 +++++++++---------- .../app/cases/create/flyout.test.tsx | 2 +- .../components/app/cases/create/flyout.tsx | 2 +- .../components/app/news_feed/index.test.tsx | 2 +- .../public/components/app/news_feed/index.tsx | 2 +- .../public/components/app/resources/index.tsx | 2 +- .../public/pages/alerts/alerts_disclaimer.tsx | 4 ++-- .../pages/alerts/alerts_table_t_grid.tsx | 2 +- .../public/pages/alerts/filter_for_value.tsx | 4 ++-- .../alerts/workflow_status_filter.test.tsx | 2 +- .../pages/alerts/workflow_status_filter.tsx | 6 ++--- .../public/pages/cases/empty_page.tsx | 8 +++---- .../pages/cases/feature_no_permissions.tsx | 2 +- .../page_objects/observability_page.ts | 4 ++-- .../services/observability/alerts/common.ts | 10 ++++---- .../observability/alerts/alert_disclaimer.ts | 4 ++-- 18 files changed, 53 insertions(+), 55 deletions(-) diff --git a/x-pack/plugins/observability/public/components/app/cases/callout/callout.test.tsx b/x-pack/plugins/observability/public/components/app/cases/callout/callout.test.tsx index b0b6fc0e3b793..25d32d0cae884 100644 --- a/x-pack/plugins/observability/public/components/app/cases/callout/callout.test.tsx +++ b/x-pack/plugins/observability/public/components/app/cases/callout/callout.test.tsx @@ -32,25 +32,25 @@ describe('Callout', () => { it('renders the callout', () => { const wrapper = mount(); - expect(wrapper.find(`[data-test-subj="case-callout-md5-hex"]`).exists()).toBeTruthy(); - expect(wrapper.find(`[data-test-subj="callout-messages-md5-hex"]`).exists()).toBeTruthy(); - expect(wrapper.find(`[data-test-subj="callout-dismiss-md5-hex"]`).exists()).toBeTruthy(); + expect(wrapper.find(`[data-test-subj="caseCallout-md5-hex"]`).exists()).toBeTruthy(); + expect(wrapper.find(`[data-test-subj="calloutMessages-md5-hex"]`).exists()).toBeTruthy(); + expect(wrapper.find(`[data-test-subj="calloutDismiss-md5-hex"]`).exists()).toBeTruthy(); }); it('hides the callout', () => { const wrapper = mount(); - expect(wrapper.find(`[data-test-subj="case-callout-md5-hex"]`).exists()).toBeFalsy(); + expect(wrapper.find(`[data-test-subj="caseCallout-md5-hex"]`).exists()).toBeFalsy(); }); it('does not show any messages when the list is empty', () => { const wrapper = mount(); - expect(wrapper.find(`[data-test-subj="callout-messages-md5-hex"]`).exists()).toBeFalsy(); + expect(wrapper.find(`[data-test-subj="calloutMessages-md5-hex"]`).exists()).toBeFalsy(); }); it('transform the button color correctly - primary', () => { const wrapper = mount(); const className = - wrapper.find(`button[data-test-subj="callout-dismiss-md5-hex"]`).first().prop('className') ?? + wrapper.find(`button[data-test-subj="calloutDismiss-md5-hex"]`).first().prop('className') ?? ''; expect(className.includes('euiButton--primary')).toBeTruthy(); }); @@ -58,7 +58,7 @@ describe('Callout', () => { it('transform the button color correctly - success', () => { const wrapper = mount(); const className = - wrapper.find(`button[data-test-subj="callout-dismiss-md5-hex"]`).first().prop('className') ?? + wrapper.find(`button[data-test-subj="calloutDismiss-md5-hex"]`).first().prop('className') ?? ''; expect(className.includes('euiButton--secondary')).toBeTruthy(); }); @@ -66,7 +66,7 @@ describe('Callout', () => { it('transform the button color correctly - warning', () => { const wrapper = mount(); const className = - wrapper.find(`button[data-test-subj="callout-dismiss-md5-hex"]`).first().prop('className') ?? + wrapper.find(`button[data-test-subj="calloutDismiss-md5-hex"]`).first().prop('className') ?? ''; expect(className.includes('euiButton--warning')).toBeTruthy(); }); @@ -74,15 +74,15 @@ describe('Callout', () => { it('transform the button color correctly - danger', () => { const wrapper = mount(); const className = - wrapper.find(`button[data-test-subj="callout-dismiss-md5-hex"]`).first().prop('className') ?? + wrapper.find(`button[data-test-subj="calloutDismiss-md5-hex"]`).first().prop('className') ?? ''; expect(className.includes('euiButton--danger')).toBeTruthy(); }); it('dismiss the callout correctly', () => { const wrapper = mount(); - expect(wrapper.find(`[data-test-subj="callout-dismiss-md5-hex"]`).exists()).toBeTruthy(); - wrapper.find(`button[data-test-subj="callout-dismiss-md5-hex"]`).simulate('click'); + expect(wrapper.find(`[data-test-subj="calloutDismiss-md5-hex"]`).exists()).toBeTruthy(); + wrapper.find(`button[data-test-subj="calloutDismiss-md5-hex"]`).simulate('click'); wrapper.update(); expect(defaultProps.handleDismissCallout).toHaveBeenCalledWith('md5-hex', 'primary'); diff --git a/x-pack/plugins/observability/public/components/app/cases/callout/callout.tsx b/x-pack/plugins/observability/public/components/app/cases/callout/callout.tsx index 5aa637c8f806d..15bd250c6ceb6 100644 --- a/x-pack/plugins/observability/public/components/app/cases/callout/callout.tsx +++ b/x-pack/plugins/observability/public/components/app/cases/callout/callout.tsx @@ -35,10 +35,10 @@ function CallOutComponent({ ); return showCallOut && !isEmpty(messages) ? ( - - + + diff --git a/x-pack/plugins/observability/public/components/app/cases/callout/index.test.tsx b/x-pack/plugins/observability/public/components/app/cases/callout/index.test.tsx index 18d4dee45b9d5..bb0284398f4b3 100644 --- a/x-pack/plugins/observability/public/components/app/cases/callout/index.test.tsx +++ b/x-pack/plugins/observability/public/components/app/cases/callout/index.test.tsx @@ -42,7 +42,7 @@ describe('CaseCallOut ', () => { ); const id = createCalloutId(['message-one', 'message-two']); - expect(wrapper.find(`[data-test-subj="callout-messages-${id}"]`).last().exists()).toBeTruthy(); + expect(wrapper.find(`[data-test-subj="calloutMessages-${id}"]`).last().exists()).toBeTruthy(); }); it('groups the messages correctly', () => { @@ -69,11 +69,9 @@ describe('CaseCallOut ', () => { const idPrimary = createCalloutId(['message-two']); expect( - wrapper.find(`[data-test-subj="case-callout-${idPrimary}"]`).last().exists() - ).toBeTruthy(); - expect( - wrapper.find(`[data-test-subj="case-callout-${idDanger}"]`).last().exists() + wrapper.find(`[data-test-subj="caseCallout-${idPrimary}"]`).last().exists() ).toBeTruthy(); + expect(wrapper.find(`[data-test-subj="caseCallout-${idDanger}"]`).last().exists()).toBeTruthy(); }); it('dismisses the callout correctly', () => { @@ -91,9 +89,9 @@ describe('CaseCallOut ', () => { const id = createCalloutId(['message-one']); - expect(wrapper.find(`[data-test-subj="case-callout-${id}"]`).last().exists()).toBeTruthy(); - wrapper.find(`[data-test-subj="callout-dismiss-${id}"]`).last().simulate('click'); - expect(wrapper.find(`[data-test-subj="case-callout-${id}"]`).exists()).toBeFalsy(); + expect(wrapper.find(`[data-test-subj="caseCallout-${id}"]`).last().exists()).toBeTruthy(); + wrapper.find(`[data-test-subj="calloutDismiss-${id}"]`).last().simulate('click'); + expect(wrapper.find(`[data-test-subj="caseCallout-${id}"]`).exists()).toBeFalsy(); }); it('persist the callout of type primary when dismissed', () => { @@ -112,7 +110,7 @@ describe('CaseCallOut ', () => { const id = createCalloutId(['message-one']); expect(securityLocalStorageMock.getMessages).toHaveBeenCalledWith(observabilityAppId); - wrapper.find(`[data-test-subj="callout-dismiss-${id}"]`).last().simulate('click'); + wrapper.find(`[data-test-subj="calloutDismiss-${id}"]`).last().simulate('click'); expect(securityLocalStorageMock.addMessage).toHaveBeenCalledWith(observabilityAppId, id); }); @@ -137,7 +135,7 @@ describe('CaseCallOut ', () => { ); - expect(wrapper.find(`[data-test-subj="case-callout-${id}"]`).last().exists()).toBeFalsy(); + expect(wrapper.find(`[data-test-subj="caseCallout-${id}"]`).last().exists()).toBeFalsy(); }); it('do not persist a callout of type danger', () => { @@ -160,7 +158,7 @@ describe('CaseCallOut ', () => { ); const id = createCalloutId(['message-one']); - wrapper.find(`button[data-test-subj="callout-dismiss-${id}"]`).simulate('click'); + wrapper.find(`button[data-test-subj="calloutDismiss-${id}"]`).simulate('click'); wrapper.update(); expect(securityLocalStorageMock.addMessage).not.toHaveBeenCalled(); }); @@ -185,7 +183,7 @@ describe('CaseCallOut ', () => { ); const id = createCalloutId(['message-one']); - wrapper.find(`button[data-test-subj="callout-dismiss-${id}"]`).simulate('click'); + wrapper.find(`button[data-test-subj="calloutDismiss-${id}"]`).simulate('click'); wrapper.update(); expect(securityLocalStorageMock.addMessage).not.toHaveBeenCalled(); }); @@ -210,7 +208,7 @@ describe('CaseCallOut ', () => { ); const id = createCalloutId(['message-one']); - wrapper.find(`button[data-test-subj="callout-dismiss-${id}"]`).simulate('click'); + wrapper.find(`button[data-test-subj="calloutDismiss-${id}"]`).simulate('click'); wrapper.update(); expect(securityLocalStorageMock.addMessage).not.toHaveBeenCalled(); }); diff --git a/x-pack/plugins/observability/public/components/app/cases/create/flyout.test.tsx b/x-pack/plugins/observability/public/components/app/cases/create/flyout.test.tsx index dc3db695a3fbf..977263a9721ea 100644 --- a/x-pack/plugins/observability/public/components/app/cases/create/flyout.test.tsx +++ b/x-pack/plugins/observability/public/components/app/cases/create/flyout.test.tsx @@ -45,7 +45,7 @@ describe('CreateCaseFlyout', () => { ); - expect(wrapper.find(`[data-test-subj='create-case-flyout']`).exists()).toBeTruthy(); + expect(wrapper.find(`[data-test-subj='createCaseFlyout']`).exists()).toBeTruthy(); }); it('Closing modal calls onCloseCaseModal', () => { diff --git a/x-pack/plugins/observability/public/components/app/cases/create/flyout.tsx b/x-pack/plugins/observability/public/components/app/cases/create/flyout.tsx index 896bc27a97674..e8147ef7098ad 100644 --- a/x-pack/plugins/observability/public/components/app/cases/create/flyout.tsx +++ b/x-pack/plugins/observability/public/components/app/cases/create/flyout.tsx @@ -54,7 +54,7 @@ function CreateCaseFlyoutComponent({ }: CreateCaseModalProps) { const { cases } = useKibana().services; return ( - +

    {i18n.CREATE_TITLE}

    diff --git a/x-pack/plugins/observability/public/components/app/news_feed/index.test.tsx b/x-pack/plugins/observability/public/components/app/news_feed/index.test.tsx index 97b5dbc679839..f6e641082e557 100644 --- a/x-pack/plugins/observability/public/components/app/news_feed/index.test.tsx +++ b/x-pack/plugins/observability/public/components/app/news_feed/index.test.tsx @@ -59,6 +59,6 @@ describe('News', () => { ); expect(getByText("What's new")).toBeInTheDocument(); expect(getAllByText('Read full story').length).toEqual(3); - expect(queryAllByTestId('news_image').length).toEqual(1); + expect(queryAllByTestId('newsImage').length).toEqual(1); }); }); diff --git a/x-pack/plugins/observability/public/components/app/news_feed/index.tsx b/x-pack/plugins/observability/public/components/app/news_feed/index.tsx index 68039f80b0b94..6f1a5f33b9ba7 100644 --- a/x-pack/plugins/observability/public/components/app/news_feed/index.tsx +++ b/x-pack/plugins/observability/public/components/app/news_feed/index.tsx @@ -85,7 +85,7 @@ function NewsItem({ item }: { item: INewsItem }) { {item.image_url?.en && (
    - + ); } diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_disclaimer.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_disclaimer.tsx index 4bf71574ea7f9..1d1aaf12cf785 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts_disclaimer.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts_disclaimer.tsx @@ -33,7 +33,7 @@ export function AlertsDisclaimer() { <> {!experimentalMsgAck && ( toggleActionsPopover(eventId)} - data-test-subj="alerts-table-row-action-more" + data-test-subj="alertsTableRowActionMore" /> } diff --git a/x-pack/plugins/observability/public/pages/alerts/filter_for_value.tsx b/x-pack/plugins/observability/public/pages/alerts/filter_for_value.tsx index f75ae488c9b28..7017f573415da 100644 --- a/x-pack/plugins/observability/public/pages/alerts/filter_for_value.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/filter_for_value.tsx @@ -35,7 +35,7 @@ const FilterForValueButton: React.FC = React.memo( Component ? ( = React.memo( { const props = { onChange, status }; const { getByTestId } = render(); - const button = getByTestId(`workflow-status-filter-${status}-button`); + const button = getByTestId(`workflowStatusFilterButton-${status}`); const input = button.querySelector('input') as Element; Simulate.change(input); diff --git a/x-pack/plugins/observability/public/pages/alerts/workflow_status_filter.tsx b/x-pack/plugins/observability/public/pages/alerts/workflow_status_filter.tsx index 20073e9937b4f..d857b9d6bd650 100644 --- a/x-pack/plugins/observability/public/pages/alerts/workflow_status_filter.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/workflow_status_filter.tsx @@ -21,7 +21,7 @@ const options: Array = label: i18n.translate('xpack.observability.alerts.workflowStatusFilter.openButtonLabel', { defaultMessage: 'Open', }), - 'data-test-subj': 'workflow-status-filter-open-button', + 'data-test-subj': 'workflowStatusFilterButton-open', }, { id: 'acknowledged', @@ -31,14 +31,14 @@ const options: Array = defaultMessage: 'Acknowledged', } ), - 'data-test-subj': 'workflow-status-filter-acknowledged-button', + 'data-test-subj': 'workflowStatusFilterButton-acknowledged', }, { id: 'closed', label: i18n.translate('xpack.observability.alerts.workflowStatusFilter.closedButtonLabel', { defaultMessage: 'Closed', }), - 'data-test-subj': 'workflow-status-filter-closed-button', + 'data-test-subj': 'workflowStatusFilterButton-closed', }, ]; diff --git a/x-pack/plugins/observability/public/pages/cases/empty_page.tsx b/x-pack/plugins/observability/public/pages/cases/empty_page.tsx index c6fc4b59ef77c..faeafa6b4730f 100644 --- a/x-pack/plugins/observability/public/pages/cases/empty_page.tsx +++ b/x-pack/plugins/observability/public/pages/cases/empty_page.tsx @@ -59,7 +59,7 @@ const EmptyPageComponent = React.memo(({ actions, message, title (({ actions, message, title iconType={icon} target={target} fill={fill} - data-test-subj={`empty-page-${titles[idx]}-action`} + data-test-subj={`emptyPageAction-${titles[idx]}`} > {label} @@ -83,7 +83,7 @@ const EmptyPageComponent = React.memo(({ actions, message, title {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} (({ actions, message, title onClick={onClick} iconType={icon} target={target} - data-test-subj={`empty-page-${titles[idx]}-action`} + data-test-subj={`emptyPageAction-${titles[idx]}`} > {label} diff --git a/x-pack/plugins/observability/public/pages/cases/feature_no_permissions.tsx b/x-pack/plugins/observability/public/pages/cases/feature_no_permissions.tsx index 5075570c15b3e..2d8631a94e04c 100644 --- a/x-pack/plugins/observability/public/pages/cases/feature_no_permissions.tsx +++ b/x-pack/plugins/observability/public/pages/cases/feature_no_permissions.tsx @@ -29,7 +29,7 @@ export const CaseFeatureNoPermissions = React.memo(() => { ); diff --git a/x-pack/test/functional/page_objects/observability_page.ts b/x-pack/test/functional/page_objects/observability_page.ts index f89dafe4f3a73..07cceca4be122 100644 --- a/x-pack/test/functional/page_objects/observability_page.ts +++ b/x-pack/test/functional/page_objects/observability_page.ts @@ -28,7 +28,7 @@ export function ObservabilityPageProvider({ getService, getPageObjects }: FtrPro }, async expectNoReadOnlyCallout() { - await testSubjects.missingOrFail('case-callout-e41900b01c9ef0fa81dd6ff326083fb3'); + await testSubjects.missingOrFail('caseCallout-e41900b01c9ef0fa81dd6ff326083fb3'); }, async expectNoDataPage() { @@ -50,7 +50,7 @@ export function ObservabilityPageProvider({ getService, getPageObjects }: FtrPro }, async expectForbidden() { - const h2 = await testSubjects.find('no_feature_permissions', 20000); + const h2 = await testSubjects.find('noFeaturePermissions', 20000); const text = await h2.getVisibleText(); expect(text).to.contain('Kibana feature privileges required'); }, diff --git a/x-pack/test/functional/services/observability/alerts/common.ts b/x-pack/test/functional/services/observability/alerts/common.ts index 8a32b41e9b8e9..373f7558f8739 100644 --- a/x-pack/test/functional/services/observability/alerts/common.ts +++ b/x-pack/test/functional/services/observability/alerts/common.ts @@ -16,7 +16,7 @@ const DATE_WITH_DATA = { }; const ALERTS_FLYOUT_SELECTOR = 'alertsFlyout'; -const FILTER_FOR_VALUE_BUTTON_SELECTOR = 'filter-for-value'; +const FILTER_FOR_VALUE_BUTTON_SELECTOR = 'filterForValue'; const ALERTS_TABLE_CONTAINER_SELECTOR = 'events-viewer-panel'; const ACTION_COLUMN_INDEX = 1; @@ -71,7 +71,7 @@ export function ObservabilityAlertsCommonProvider({ }; const getExperimentalDisclaimer = async () => { - return testSubjects.existOrFail('o11y-experimental-disclaimer'); + return testSubjects.existOrFail('o11yExperimentalDisclaimer'); }; const getTableCellsInRows = async () => { @@ -173,7 +173,7 @@ export function ObservabilityAlertsCommonProvider({ const openActionsMenuForRow = async (rowIndex: number) => { const rows = await getTableCellsInRows(); const actionsOverflowButton = await testSubjects.findDescendant( - 'alerts-table-row-action-more', + 'alertsTableRowActionMore', rows[rowIndex][ACTION_COLUMN_INDEX] ); await actionsOverflowButton.click(); @@ -196,7 +196,7 @@ export function ObservabilityAlertsCommonProvider({ const setWorkflowStatusFilter = async (workflowStatus: WorkflowStatus) => { const buttonGroupButton = await testSubjects.find( - `workflow-status-filter-${workflowStatus}-button` + `workflowStatusFilterButton-${workflowStatus}` ); await buttonGroupButton.click(); }; @@ -223,7 +223,7 @@ export function ObservabilityAlertsCommonProvider({ const getActionsButtonByIndex = async (index: number) => { const actionsOverflowButtons = await find.allByCssSelector( - '[data-test-subj="alerts-table-row-action-more"]' + '[data-test-subj="alertsTableRowActionMore"]' ); return actionsOverflowButtons[index] || null; }; diff --git a/x-pack/test/observability_functional/apps/observability/alerts/alert_disclaimer.ts b/x-pack/test/observability_functional/apps/observability/alerts/alert_disclaimer.ts index c687210286304..d63739da47d5b 100644 --- a/x-pack/test/observability_functional/apps/observability/alerts/alert_disclaimer.ts +++ b/x-pack/test/observability_functional/apps/observability/alerts/alert_disclaimer.ts @@ -34,8 +34,8 @@ export default ({ getService, getPageObject }: FtrProviderContext) => { }); it('Dismiss experimental disclaimer', async () => { - await testSubjects.click('o11y-experimental-disclaimer-dismiss-btn'); - const o11yExperimentalDisclaimer = await testSubjects.exists('o11y-experimental-disclaimer'); + await testSubjects.click('o11yExperimentalDisclaimerDismissBtn'); + const o11yExperimentalDisclaimer = await testSubjects.exists('o11yExperimentalDisclaimer'); expect(o11yExperimentalDisclaimer).not.to.be(null); }); }); From 6f5faf93f06039f04d6cbec2f667adebd064c59a Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 10 Nov 2021 21:11:39 +0100 Subject: [PATCH 14/51] [Exploratory view] Show index pattern permission error (#117539) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../hooks/use_app_index_pattern.tsx | 15 +++++++++++++-- .../shared/exploratory_view/rtl_helpers.tsx | 1 + .../series_editor/report_metric_options.tsx | 19 ++++++++++++++++++- .../utils/observability_index_patterns.ts | 1 - 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx index 8a766075ef8d2..9bd611c05e956 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx @@ -6,6 +6,7 @@ */ import React, { createContext, useContext, Context, useState, useCallback, useMemo } from 'react'; +import { HttpFetchError } from 'kibana/public'; import { IndexPattern } from '../../../../../../../../src/plugins/data/common'; import { AppDataType } from '../types'; import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; @@ -16,6 +17,7 @@ import { getDataHandler } from '../../../../data_handler'; export interface IndexPatternContext { loading: boolean; indexPatterns: IndexPatternState; + indexPatternErrors: IndexPatternErrors; hasAppData: HasAppDataState; loadIndexPattern: (params: { dataType: AppDataType }) => void; } @@ -28,11 +30,15 @@ interface ProviderProps { type HasAppDataState = Record; export type IndexPatternState = Record; +export type IndexPatternErrors = Record; type LoadingState = Record; export function IndexPatternContextProvider({ children }: ProviderProps) { const [loading, setLoading] = useState({} as LoadingState); const [indexPatterns, setIndexPatterns] = useState({} as IndexPatternState); + const [indexPatternErrors, setIndexPatternErrors] = useState( + {} as IndexPatternErrors + ); const [hasAppData, setHasAppData] = useState({ infra_metrics: null, infra_logs: null, @@ -78,6 +84,9 @@ export function IndexPatternContextProvider({ children }: ProviderProps) { } setLoading((prevState) => ({ ...prevState, [dataType]: false })); } catch (e) { + if ((e as HttpFetchError).body.error === 'Forbidden') { + setIndexPatternErrors((prevState) => ({ ...prevState, [dataType]: e })); + } setLoading((prevState) => ({ ...prevState, [dataType]: false })); } } @@ -91,6 +100,7 @@ export function IndexPatternContextProvider({ children }: ProviderProps) { hasAppData, indexPatterns, loadIndexPattern, + indexPatternErrors, loading: !!Object.values(loading).find((loadingT) => loadingT), }} > @@ -100,7 +110,7 @@ export function IndexPatternContextProvider({ children }: ProviderProps) { } export const useAppIndexPatternContext = (dataType?: AppDataType) => { - const { loading, hasAppData, loadIndexPattern, indexPatterns } = useContext( + const { loading, hasAppData, loadIndexPattern, indexPatterns, indexPatternErrors } = useContext( IndexPatternContext as unknown as Context ); @@ -113,9 +123,10 @@ export const useAppIndexPatternContext = (dataType?: AppDataType) => { hasAppData, loading, indexPatterns, + indexPatternErrors, indexPattern: dataType ? indexPatterns?.[dataType] : undefined, hasData: dataType ? hasAppData?.[dataType] : undefined, loadIndexPattern, }; - }, [dataType, hasAppData, indexPatterns, loadIndexPattern, loading]); + }, [dataType, hasAppData, indexPatternErrors, indexPatterns, loadIndexPattern, loading]); }; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx index efca1152e175d..612cbfcc4bfdf 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx @@ -243,6 +243,7 @@ export const mockAppIndexPattern = () => { hasAppData: { ux: true } as any, loadIndexPattern, indexPatterns: { ux: mockIndexPattern } as unknown as Record, + indexPatternErrors: {} as any, }); return { spy, loadIndexPattern }; }; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.tsx index eca18f0eb0dd4..410356d0078d8 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.tsx @@ -35,7 +35,7 @@ export function ReportMetricOptions({ seriesId, series, seriesConfig }: Props) { const [showOptions, setShowOptions] = useState(false); const metricOptions = seriesConfig?.metricOptions; - const { indexPatterns, loading } = useAppIndexPatternContext(); + const { indexPatterns, indexPatternErrors, loading } = useAppIndexPatternContext(); const onChange = (value?: string) => { setSeries(seriesId, { @@ -49,6 +49,7 @@ export function ReportMetricOptions({ seriesId, series, seriesConfig }: Props) { } const indexPattern = indexPatterns?.[series.dataType]; + const indexPatternError = indexPatternErrors?.[series.dataType]; const options = (metricOptions ?? []).map(({ label, field, id }) => { let disabled = false; @@ -80,6 +81,17 @@ export function ReportMetricOptions({ seriesId, series, seriesConfig }: Props) { }; }); + if (indexPatternError && !indexPattern && !loading) { + // TODO: Add a link to docs to explain how to add index patterns + return ( + + {indexPatternError.body.error === 'Forbidden' + ? NO_PERMISSIONS + : indexPatternError.body.message} + + ); + } + if (!indexPattern && !loading) { return {NO_DATA_AVAILABLE}; } @@ -152,3 +164,8 @@ const REMOVE_REPORT_METRIC_LABEL = i18n.translate( const NO_DATA_AVAILABLE = i18n.translate('xpack.observability.expView.seriesEditor.noData', { defaultMessage: 'No data available', }); + +const NO_PERMISSIONS = i18n.translate('xpack.observability.expView.seriesEditor.noPermissions', { + defaultMessage: + "Unable to create Index Pattern. You don't have the required permission, please contact your admin.", +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts index b61af3a61c3dc..f591ef63a61fb 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts @@ -86,7 +86,6 @@ export class ObservabilityIndexPatterns { } const appIndicesPattern = getAppIndicesWithPattern(app, indices); - return await this.data.indexPatterns.createAndSave({ title: appIndicesPattern, id: getAppIndexPatternId(app, indices), From bde802fed655cdffe8700480007aa8a6bd91d43c Mon Sep 17 00:00:00 2001 From: Jason Stoltzfus Date: Wed, 10 Nov 2021 15:20:57 -0500 Subject: [PATCH 15/51] [Enterprise Search] Added a test helper #117948 --- .../analytics/analytics_logic.test.ts | 24 ++----- .../api_logs/api_logs_logic.test.ts | 11 ++- .../crawler/crawler_domains_logic.test.ts | 9 +-- .../components/crawler/crawler_logic.test.ts | 25 ++----- .../crawler_single_domain_logic.test.ts | 25 ++----- .../credentials/credentials_logic.test.ts | 31 ++------- .../components/suggestions_logic.test.tsx | 16 ++--- .../curations/curation/curation_logic.test.ts | 17 ++--- .../curations/curations_logic.test.ts | 9 +-- .../curation_suggestion_logic.test.ts | 27 +++----- .../ignored_queries_logic.test.ts | 20 ++---- .../curations_settings_logic.test.ts | 24 ++----- .../documents/document_detail_logic.test.ts | 9 +-- .../engine_overview_logic.test.ts | 16 ++--- .../components/engines/engines_logic.test.ts | 15 +--- .../relevance_tuning_logic.test.ts | 9 +-- .../result_settings_logic.test.ts | 23 ++----- .../role_mappings/role_mappings_logic.test.ts | 22 ++---- .../schema/schema_base_logic.test.ts | 16 ++--- .../search_ui/search_ui_logic.test.ts | 11 ++- .../synonyms/synonyms_logic.test.ts | 9 +-- .../recursively_fetch_engines/index.test.ts | 12 ++-- ...dpoint_inline_editable_table_logic.test.ts | 23 ++----- .../test_helpers/error_handling.ts | 22 ++++++ .../public/applications/test_helpers/index.ts | 1 + .../add_source/add_source_logic.test.ts | 37 ++-------- .../display_settings_logic.test.ts | 16 ++--- .../components/schema/schema_logic.test.ts | 16 ++--- .../synchronization_logic.test.ts | 17 +---- .../content_sources/source_logic.test.ts | 69 ++----------------- .../content_sources/sources_logic.test.ts | 42 ++--------- .../views/groups/group_logic.test.ts | 32 ++------- .../views/groups/groups_logic.test.ts | 23 ++----- .../role_mappings/role_mappings_logic.test.ts | 14 ++-- .../views/security/security_logic.test.ts | 27 ++------ .../views/settings/settings_logic.test.ts | 45 +++--------- 36 files changed, 185 insertions(+), 579 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/test_helpers/error_handling.ts diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_logic.test.ts index 7b877419a2977..62ba44128663a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_logic.test.ts @@ -5,12 +5,7 @@ * 2.0. */ -import { - LogicMounter, - mockKibanaValues, - mockHttpValues, - mockFlashMessageHelpers, -} from '../../../__mocks__/kea_logic'; +import { LogicMounter, mockKibanaValues, mockHttpValues } from '../../../__mocks__/kea_logic'; jest.mock('../engine', () => ({ EngineLogic: { values: { engineName: 'test-engine' } }, @@ -18,6 +13,8 @@ jest.mock('../engine', () => ({ import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { DEFAULT_START_DATE, DEFAULT_END_DATE } from './constants'; import { AnalyticsLogic } from './'; @@ -26,7 +23,6 @@ describe('AnalyticsLogic', () => { const { mount } = new LogicMounter(AnalyticsLogic); const { history } = mockKibanaValues; const { http } = mockHttpValues; - const { flashAPIErrors } = mockFlashMessageHelpers; const DEFAULT_VALUES = { dataLoading: true, @@ -197,14 +193,9 @@ describe('AnalyticsLogic', () => { ); }); - it('handles errors', async () => { - http.get.mockReturnValueOnce(Promise.reject('error')); + itShowsServerErrorAsFlashMessage(http.get, () => { mount(); - AnalyticsLogic.actions.loadAnalyticsData(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); @@ -259,14 +250,9 @@ describe('AnalyticsLogic', () => { ); }); - it('handles errors', async () => { - http.get.mockReturnValueOnce(Promise.reject('error')); + itShowsServerErrorAsFlashMessage(http.get, () => { mount(); - AnalyticsLogic.actions.loadQueryData('some-query'); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs_logic.test.ts index 2f3aedc8fa11d..51d51b5aee88c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs_logic.test.ts @@ -17,12 +17,14 @@ import { nextTick } from '@kbn/test/jest'; import { DEFAULT_META } from '../../../shared/constants'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { ApiLogsLogic } from './'; describe('ApiLogsLogic', () => { const { mount, unmount } = new LogicMounter(ApiLogsLogic); const { http } = mockHttpValues; - const { flashAPIErrors, flashErrorToast } = mockFlashMessageHelpers; + const { flashErrorToast } = mockFlashMessageHelpers; const DEFAULT_VALUES = { dataLoading: true, @@ -176,14 +178,9 @@ describe('ApiLogsLogic', () => { expect(ApiLogsLogic.actions.updateView).toHaveBeenCalledWith(MOCK_API_RESPONSE); }); - it('handles API errors', async () => { - http.get.mockReturnValueOnce(Promise.reject('error')); + itShowsServerErrorAsFlashMessage(http.get, () => { mount(); - ApiLogsLogic.actions.fetchApiLogs(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_domains_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_domains_logic.test.ts index 6cf2f21fc6d2e..fda96ca5f8381 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_domains_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_domains_logic.test.ts @@ -18,6 +18,8 @@ import { Meta } from '../../../../../common/types'; import { DEFAULT_META } from '../../../shared/constants'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers/error_handling'; + import { CrawlerDomainsLogic, CrawlerDomainsValues } from './crawler_domains_logic'; import { CrawlerDataFromServer, CrawlerDomain, CrawlerDomainFromServer } from './types'; import { crawlerDataServerToClient } from './utils'; @@ -193,13 +195,8 @@ describe('CrawlerDomainsLogic', () => { ); }); - it('calls flashApiErrors when there is an error', async () => { - http.delete.mockReturnValue(Promise.reject('error')); - + itShowsServerErrorAsFlashMessage(http.delete, () => { CrawlerDomainsLogic.actions.deleteDomain({ id: '1234' } as CrawlerDomain); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_logic.test.ts index 7ba1adb51bbfb..b2321073f3d95 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_logic.test.ts @@ -14,6 +14,8 @@ import '../../__mocks__/engine_logic.mock'; import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { CrawlerDomainsLogic } from './crawler_domains_logic'; import { CrawlerLogic, CrawlerValues } from './crawler_logic'; import { @@ -280,15 +282,8 @@ describe('CrawlerLogic', () => { }); }); - describe('on failure', () => { - it('flashes an error message', async () => { - http.post.mockReturnValueOnce(Promise.reject('error')); - - CrawlerLogic.actions.startCrawl(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); - }); + itShowsServerErrorAsFlashMessage(http.post, () => { + CrawlerLogic.actions.startCrawl(); }); }); @@ -308,16 +303,8 @@ describe('CrawlerLogic', () => { }); }); - describe('on failure', () => { - it('flashes an error message', async () => { - jest.spyOn(CrawlerLogic.actions, 'fetchCrawlerData'); - http.post.mockReturnValueOnce(Promise.reject('error')); - - CrawlerLogic.actions.stopCrawl(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); - }); + itShowsServerErrorAsFlashMessage(http.post, () => { + CrawlerLogic.actions.stopCrawl(); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_single_domain_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_single_domain_logic.test.ts index 03e20ea988f98..547218ad6a2c1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_single_domain_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/crawler_single_domain_logic.test.ts @@ -23,6 +23,8 @@ jest.mock('./crawler_logic', () => ({ import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { CrawlerLogic } from './crawler_logic'; import { CrawlerSingleDomainLogic, CrawlerSingleDomainValues } from './crawler_single_domain_logic'; import { CrawlerDomain, CrawlerPolicies, CrawlerRules } from './types'; @@ -35,7 +37,7 @@ const DEFAULT_VALUES: CrawlerSingleDomainValues = { describe('CrawlerSingleDomainLogic', () => { const { mount } = new LogicMounter(CrawlerSingleDomainLogic); const { http } = mockHttpValues; - const { flashAPIErrors, flashSuccessToast } = mockFlashMessageHelpers; + const { flashSuccessToast } = mockFlashMessageHelpers; beforeEach(() => { jest.clearAllMocks(); @@ -176,13 +178,8 @@ describe('CrawlerSingleDomainLogic', () => { expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/crawler'); }); - it('calls flashApiErrors when there is an error', async () => { - http.delete.mockReturnValue(Promise.reject('error')); - + itShowsServerErrorAsFlashMessage(http.delete, () => { CrawlerSingleDomainLogic.actions.deleteDomain({ id: '1234' } as CrawlerDomain); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); @@ -218,13 +215,8 @@ describe('CrawlerSingleDomainLogic', () => { }); }); - it('displays any errors to the user', async () => { - http.get.mockReturnValueOnce(Promise.reject('error')); - + itShowsServerErrorAsFlashMessage(http.get, () => { CrawlerSingleDomainLogic.actions.fetchDomainData('507f1f77bcf86cd799439011'); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); @@ -272,16 +264,11 @@ describe('CrawlerSingleDomainLogic', () => { }); }); - it('displays any errors to the user', async () => { - http.put.mockReturnValueOnce(Promise.reject('error')); - + itShowsServerErrorAsFlashMessage(http.put, () => { CrawlerSingleDomainLogic.actions.submitDeduplicationUpdate( { id: '507f1f77bcf86cd799439011' } as CrawlerDomain, { fields: ['title'], enabled: true } ); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts index 3afa531239dc1..decb98d227975 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts @@ -20,6 +20,7 @@ jest.mock('../../app_logic', () => ({ selectors: { myRole: jest.fn(() => ({})) }, }, })); +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; import { AppLogic } from '../../app_logic'; import { EngineTypes } from '../engine/types'; @@ -31,7 +32,7 @@ import { CredentialsLogic } from './credentials_logic'; describe('CredentialsLogic', () => { const { mount } = new LogicMounter(CredentialsLogic); const { http } = mockHttpValues; - const { clearFlashMessages, flashSuccessToast, flashAPIErrors } = mockFlashMessageHelpers; + const { clearFlashMessages, flashSuccessToast } = mockFlashMessageHelpers; const DEFAULT_VALUES = { activeApiToken: { @@ -1059,14 +1060,9 @@ describe('CredentialsLogic', () => { expect(CredentialsLogic.actions.setCredentialsData).toHaveBeenCalledWith(meta, results); }); - it('handles errors', async () => { + itShowsServerErrorAsFlashMessage(http.get, () => { mount(); - http.get.mockReturnValue(Promise.reject('An error occured')); - CredentialsLogic.actions.fetchCredentials(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('An error occured'); }); }); @@ -1086,14 +1082,9 @@ describe('CredentialsLogic', () => { ); }); - it('handles errors', async () => { + itShowsServerErrorAsFlashMessage(http.get, () => { mount(); - http.get.mockReturnValue(Promise.reject('An error occured')); - CredentialsLogic.actions.fetchDetails(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('An error occured'); }); }); @@ -1113,14 +1104,9 @@ describe('CredentialsLogic', () => { expect(flashSuccessToast).toHaveBeenCalled(); }); - it('handles errors', async () => { + itShowsServerErrorAsFlashMessage(http.delete, () => { mount(); - http.delete.mockReturnValue(Promise.reject('An error occured')); - CredentialsLogic.actions.deleteApiKey(tokenName); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('An error occured'); }); }); @@ -1172,14 +1158,9 @@ describe('CredentialsLogic', () => { expect(flashSuccessToast).toHaveBeenCalled(); }); - it('handles errors', async () => { + itShowsServerErrorAsFlashMessage(http.post, () => { mount(); - http.post.mockReturnValue(Promise.reject('An error occured')); - CredentialsLogic.actions.onApiTokenChange(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('An error occured'); }); describe('token type data', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_logic.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_logic.test.tsx index 3e12aa7b629f0..a3ca646bd9f54 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_logic.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_logic.test.tsx @@ -5,17 +5,15 @@ * 2.0. */ -import { - LogicMounter, - mockFlashMessageHelpers, - mockHttpValues, -} from '../../../../__mocks__/kea_logic'; +import { LogicMounter, mockHttpValues } from '../../../../__mocks__/kea_logic'; import '../../../__mocks__/engine_logic.mock'; import { nextTick } from '@kbn/test/jest'; import { DEFAULT_META } from '../../../../shared/constants'; +import { itShowsServerErrorAsFlashMessage } from '../../../../test_helpers'; + import { SuggestionsAPIResponse, SuggestionsLogic } from './suggestions_logic'; const DEFAULT_VALUES = { @@ -52,7 +50,6 @@ const MOCK_RESPONSE: SuggestionsAPIResponse = { describe('SuggestionsLogic', () => { const { mount } = new LogicMounter(SuggestionsLogic); - const { flashAPIErrors } = mockFlashMessageHelpers; const { http } = mockHttpValues; beforeEach(() => { @@ -140,14 +137,9 @@ describe('SuggestionsLogic', () => { expect(SuggestionsLogic.actions.onSuggestionsLoaded).toHaveBeenCalledWith(MOCK_RESPONSE); }); - it('handles errors', async () => { - http.post.mockReturnValueOnce(Promise.reject('error')); + itShowsServerErrorAsFlashMessage(http.post, () => { mount(); - SuggestionsLogic.actions.loadSuggestions(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts index 2b51cbb884ff9..644139250c07c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts @@ -15,6 +15,8 @@ import '../../../__mocks__/engine_logic.mock'; import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../../test_helpers'; + import { CurationLogic } from './'; describe('CurationLogic', () => { @@ -309,14 +311,8 @@ describe('CurationLogic', () => { expect(CurationLogic.actions.loadCuration).toHaveBeenCalled(); }); - it('flashes any error messages', async () => { - http.put.mockReturnValueOnce(Promise.reject('error')); - mount({ activeQuery: 'some query' }); - + itShowsServerErrorAsFlashMessage(http.put, () => { CurationLogic.actions.convertToManual(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); @@ -336,14 +332,9 @@ describe('CurationLogic', () => { expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations'); }); - it('flashes any errors', async () => { - http.delete.mockReturnValueOnce(Promise.reject('error')); + itShowsServerErrorAsFlashMessage(http.delete, () => { mount({}, { curationId: 'cur-404' }); - CurationLogic.actions.deleteCuration(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.test.ts index 44ff66e5f46eb..71d8b65f1a639 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.test.ts @@ -17,6 +17,8 @@ import { nextTick } from '@kbn/test/jest'; import { DEFAULT_META } from '../../../shared/constants'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { CurationsLogic } from './'; describe('CurationsLogic', () => { @@ -130,14 +132,9 @@ describe('CurationsLogic', () => { ); }); - it('handles errors', async () => { - http.get.mockReturnValueOnce(Promise.reject('error')); + itShowsServerErrorAsFlashMessage(http.get, () => { mount(); - CurationsLogic.actions.loadCurations(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts index 171c774d8add2..01d8107067e18 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts @@ -16,6 +16,7 @@ import '../../../../__mocks__/engine_logic.mock'; import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../../../test_helpers'; import { HydratedCurationSuggestion } from '../../types'; import { CurationSuggestionLogic } from './curation_suggestion_logic'; @@ -180,20 +181,6 @@ describe('CurationSuggestionLogic', () => { }); }; - const itHandlesErrors = (httpMethod: any, callback: () => void) => { - it('handles errors', async () => { - httpMethod.mockReturnValueOnce(Promise.reject('error')); - mountLogic({ - suggestion, - }); - - callback(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); - }); - }; - beforeEach(() => { jest.clearAllMocks(); }); @@ -271,7 +258,7 @@ describe('CurationSuggestionLogic', () => { expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations'); }); - itHandlesErrors(http.get, () => { + itShowsServerErrorAsFlashMessage(http.get, () => { CurationSuggestionLogic.actions.loadSuggestion(); }); }); @@ -350,7 +337,8 @@ describe('CurationSuggestionLogic', () => { }); }); - itHandlesErrors(http.put, () => { + itShowsServerErrorAsFlashMessage(http.put, () => { + jest.spyOn(global, 'confirm').mockReturnValueOnce(true); CurationSuggestionLogic.actions.acceptSuggestion(); }); @@ -433,7 +421,8 @@ describe('CurationSuggestionLogic', () => { }); }); - itHandlesErrors(http.put, () => { + itShowsServerErrorAsFlashMessage(http.put, () => { + jest.spyOn(global, 'confirm').mockReturnValueOnce(true); CurationSuggestionLogic.actions.acceptAndAutomateSuggestion(); }); @@ -478,7 +467,7 @@ describe('CurationSuggestionLogic', () => { expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations'); }); - itHandlesErrors(http.put, () => { + itShowsServerErrorAsFlashMessage(http.put, () => { CurationSuggestionLogic.actions.rejectSuggestion(); }); @@ -523,7 +512,7 @@ describe('CurationSuggestionLogic', () => { expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations'); }); - itHandlesErrors(http.put, () => { + itShowsServerErrorAsFlashMessage(http.put, () => { CurationSuggestionLogic.actions.rejectAndDisableSuggestion(); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_history/components/ignored_queries_panel/ignored_queries_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_history/components/ignored_queries_panel/ignored_queries_logic.test.ts index 8c2545fad651a..af9f876820790 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_history/components/ignored_queries_panel/ignored_queries_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_history/components/ignored_queries_panel/ignored_queries_logic.test.ts @@ -11,13 +11,13 @@ import { mockHttpValues, } from '../../../../../../../__mocks__/kea_logic'; import '../../../../../../__mocks__/engine_logic.mock'; +import { DEFAULT_META } from '../../../../../../../shared/constants'; +import { itShowsServerErrorAsFlashMessage } from '../../../../../../../test_helpers'; // I don't know why eslint is saying this line is out of order // eslint-disable-next-line import/order import { nextTick } from '@kbn/test/jest'; -import { DEFAULT_META } from '../../../../../../../shared/constants'; - import { IgnoredQueriesLogic } from './ignored_queries_logic'; const DEFAULT_VALUES = { @@ -142,13 +142,9 @@ describe('IgnoredQueriesLogic', () => { ); }); - it('handles errors', async () => { - http.post.mockReturnValueOnce(Promise.reject('error')); - + itShowsServerErrorAsFlashMessage(http.post, () => { + mount(); IgnoredQueriesLogic.actions.loadIgnoredQueries(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); @@ -185,13 +181,9 @@ describe('IgnoredQueriesLogic', () => { expect(flashSuccessToast).toHaveBeenCalledWith(expect.any(String)); }); - it('handles errors', async () => { - http.put.mockReturnValueOnce(Promise.reject('error')); - + itShowsServerErrorAsFlashMessage(http.put, () => { + mount(); IgnoredQueriesLogic.actions.allowIgnoredQuery('test query'); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); it('handles inline errors', async () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings_logic.test.ts index 0d09f2d28f396..e9643f92f2f71 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings_logic.test.ts @@ -5,11 +5,7 @@ * 2.0. */ -import { - LogicMounter, - mockHttpValues, - mockFlashMessageHelpers, -} from '../../../../../__mocks__/kea_logic'; +import { LogicMounter, mockHttpValues } from '../../../../../__mocks__/kea_logic'; import '../../../../__mocks__/engine_logic.mock'; jest.mock('../../curations_logic', () => ({ @@ -24,6 +20,7 @@ jest.mock('../../curations_logic', () => ({ import { nextTick } from '@kbn/test/jest'; import { CurationsLogic } from '../..'; +import { itShowsServerErrorAsFlashMessage } from '../../../../../test_helpers'; import { EngineLogic } from '../../../engine'; import { CurationsSettingsLogic } from './curations_settings_logic'; @@ -39,7 +36,6 @@ const DEFAULT_VALUES = { describe('CurationsSettingsLogic', () => { const { mount } = new LogicMounter(CurationsSettingsLogic); const { http } = mockHttpValues; - const { flashAPIErrors } = mockFlashMessageHelpers; beforeEach(() => { jest.clearAllMocks(); @@ -105,14 +101,8 @@ describe('CurationsSettingsLogic', () => { }); }); - it('presents any API errors to the user', async () => { - http.get.mockReturnValueOnce(Promise.reject('error')); - mount(); - + itShowsServerErrorAsFlashMessage(http.get, () => { CurationsSettingsLogic.actions.loadCurationsSettings(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); @@ -223,14 +213,8 @@ describe('CurationsSettingsLogic', () => { expect(CurationsLogic.actions.loadCurations).toHaveBeenCalled(); }); - it('presents any API errors to the user', async () => { - http.put.mockReturnValueOnce(Promise.reject('error')); - mount(); - + itShowsServerErrorAsFlashMessage(http.put, () => { CurationsSettingsLogic.actions.updateCurationsSetting({}); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail_logic.test.ts index 5705e5ae2ee98..848a85f23c2cb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail_logic.test.ts @@ -17,6 +17,8 @@ import { nextTick } from '@kbn/test/jest'; import { InternalSchemaType } from '../../../shared/schema/types'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { DocumentDetailLogic } from './document_detail_logic'; describe('DocumentDetailLogic', () => { @@ -117,14 +119,9 @@ describe('DocumentDetailLogic', () => { await nextTick(); }); - it('handles errors', async () => { + itShowsServerErrorAsFlashMessage(http.delete, () => { mount(); - http.delete.mockReturnValue(Promise.reject('An error occured')); - DocumentDetailLogic.actions.deleteDocument('1'); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('An error occured'); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_logic.test.ts index e742fce0532ba..142aab98a643b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_logic.test.ts @@ -5,11 +5,7 @@ * 2.0. */ -import { - LogicMounter, - mockHttpValues, - mockFlashMessageHelpers, -} from '../../../__mocks__/kea_logic'; +import { LogicMounter, mockHttpValues } from '../../../__mocks__/kea_logic'; jest.mock('../engine', () => ({ EngineLogic: { values: { engineName: 'some-engine' } }, @@ -17,12 +13,13 @@ jest.mock('../engine', () => ({ import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { EngineOverviewLogic } from './'; describe('EngineOverviewLogic', () => { const { mount } = new LogicMounter(EngineOverviewLogic); const { http } = mockHttpValues; - const { flashAPIErrors } = mockFlashMessageHelpers; const mockEngineMetrics = { documentCount: 10, @@ -83,14 +80,9 @@ describe('EngineOverviewLogic', () => { ); }); - it('handles errors', async () => { + itShowsServerErrorAsFlashMessage(http.get, () => { mount(); - http.get.mockReturnValue(Promise.reject('An error occurred')); - EngineOverviewLogic.actions.loadOverviewMetrics(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('An error occurred'); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_logic.test.ts index f3dc8a378a7d3..d0a227c8c6fbe 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_logic.test.ts @@ -15,6 +15,7 @@ import { nextTick } from '@kbn/test/jest'; import { DEFAULT_META } from '../../../shared/constants'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; import { EngineDetails, EngineTypes } from '../engine/types'; import { EnginesLogic } from './'; @@ -171,14 +172,9 @@ describe('EnginesLogic', () => { expect(EnginesLogic.actions.onEnginesLoad).toHaveBeenCalledWith(MOCK_ENGINES_API_RESPONSE); }); - it('handles errors', async () => { - http.get.mockReturnValueOnce(Promise.reject('error')); + itShowsServerErrorAsFlashMessage(http.get, () => { mount(); - EnginesLogic.actions.loadEngines(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); @@ -203,14 +199,9 @@ describe('EnginesLogic', () => { ); }); - it('handles errors', async () => { - http.get.mockReturnValueOnce(Promise.reject('error')); + itShowsServerErrorAsFlashMessage(http.get, () => { mount(); - EnginesLogic.actions.loadMetaEngines(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts index 193c5dbe8ac24..6ac1c27a27959 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts @@ -14,6 +14,8 @@ import { mockEngineValues, mockEngineActions } from '../../__mocks__'; import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { Boost, BoostOperation, BoostType, FunctionalBoostFunction } from './types'; import { RelevanceTuningLogic } from './'; @@ -319,14 +321,9 @@ describe('RelevanceTuningLogic', () => { }); }); - it('handles errors', async () => { + itShowsServerErrorAsFlashMessage(http.get, () => { mount(); - http.get.mockReturnValueOnce(Promise.reject('error')); - RelevanceTuningLogic.actions.initializeRelevanceTuning(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.test.ts index 94d5e84c67f6d..92cb2346e0a26 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.test.ts @@ -5,11 +5,7 @@ * 2.0. */ -import { - LogicMounter, - mockFlashMessageHelpers, - mockHttpValues, -} from '../../../__mocks__/kea_logic'; +import { LogicMounter, mockHttpValues } from '../../../__mocks__/kea_logic'; import { mockEngineValues } from '../../__mocks__'; import { omit } from 'lodash'; @@ -18,6 +14,8 @@ import { nextTick } from '@kbn/test/jest'; import { Schema, SchemaConflicts, SchemaType } from '../../../shared/schema/types'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { ServerFieldResultSettingObject } from './types'; import { ResultSettingsLogic } from '.'; @@ -508,7 +506,6 @@ describe('ResultSettingsLogic', () => { describe('listeners', () => { const { http } = mockHttpValues; - const { flashAPIErrors } = mockFlashMessageHelpers; let confirmSpy: jest.SpyInstance; beforeAll(() => { @@ -844,14 +841,9 @@ describe('ResultSettingsLogic', () => { ); }); - it('handles errors', async () => { + itShowsServerErrorAsFlashMessage(http.get, () => { mount(); - http.get.mockReturnValueOnce(Promise.reject('error')); - ResultSettingsLogic.actions.initializeResultSettingsData(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); @@ -923,14 +915,9 @@ describe('ResultSettingsLogic', () => { ); }); - it('handles errors', async () => { + itShowsServerErrorAsFlashMessage(http.put, () => { mount(); - http.put.mockReturnValueOnce(Promise.reject('error')); - ResultSettingsLogic.actions.saveResultSettings(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); it('does nothing if the user does not confirm', async () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings_logic.test.ts index 14d97c7dd3f4d..b35865f279817 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings_logic.test.ts @@ -23,13 +23,15 @@ import { } from '../../../shared/role_mapping/__mocks__/roles'; import { ANY_AUTH_PROVIDER } from '../../../shared/role_mapping/constants'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { RoleMappingsLogic } from './role_mappings_logic'; const emptyUser = { username: '', email: '' }; describe('RoleMappingsLogic', () => { const { http } = mockHttpValues; - const { clearFlashMessages, flashAPIErrors, flashSuccessToast } = mockFlashMessageHelpers; + const { clearFlashMessages, flashSuccessToast } = mockFlashMessageHelpers; const { mount } = new LogicMounter(RoleMappingsLogic); const DEFAULT_VALUES = { attributes: [], @@ -391,12 +393,8 @@ describe('RoleMappingsLogic', () => { expect(setRoleMappingsSpy).toHaveBeenCalledWith(mappingsServerProps); }); - it('handles error', async () => { - http.post.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.post, () => { RoleMappingsLogic.actions.enableRoleBasedAccess(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -411,12 +409,8 @@ describe('RoleMappingsLogic', () => { expect(setRoleMappingsDataSpy).toHaveBeenCalledWith(mappingsServerProps); }); - it('handles error', async () => { - http.get.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.get, () => { RoleMappingsLogic.actions.initializeRoleMappings(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); it('resets roleMapping state', () => { @@ -691,13 +685,9 @@ describe('RoleMappingsLogic', () => { expect(flashSuccessToast).toHaveBeenCalled(); }); - it('handles error', async () => { + itShowsServerErrorAsFlashMessage(http.delete, () => { mount(mappingsServerProps); - http.delete.mockReturnValue(Promise.reject('this is an error')); RoleMappingsLogic.actions.handleDeleteMapping(roleMappingId); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/schema/schema_base_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/schema/schema_base_logic.test.ts index c5611420442c8..5b40b362bc665 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/schema/schema_base_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/schema/schema_base_logic.test.ts @@ -5,23 +5,20 @@ * 2.0. */ -import { - LogicMounter, - mockFlashMessageHelpers, - mockHttpValues, -} from '../../../__mocks__/kea_logic'; +import { LogicMounter, mockHttpValues } from '../../../__mocks__/kea_logic'; import '../../__mocks__/engine_logic.mock'; import { nextTick } from '@kbn/test/jest'; import { SchemaType } from '../../../shared/schema/types'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { SchemaBaseLogic } from './schema_base_logic'; describe('SchemaBaseLogic', () => { const { mount } = new LogicMounter(SchemaBaseLogic); const { http } = mockHttpValues; - const { flashAPIErrors } = mockFlashMessageHelpers; const MOCK_SCHEMA = { some_text_field: SchemaType.Text, @@ -99,14 +96,9 @@ describe('SchemaBaseLogic', () => { expect(SchemaBaseLogic.actions.onSchemaLoad).toHaveBeenCalledWith(MOCK_RESPONSE); }); - it('handles errors', async () => { - http.get.mockReturnValueOnce(Promise.reject('error')); + itShowsServerErrorAsFlashMessage(http.get, () => { mount(); - SchemaBaseLogic.actions.loadSchema(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui_logic.test.ts index 33144d4188ec1..49444fbd0c5c5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui_logic.test.ts @@ -14,6 +14,8 @@ import { mockEngineValues } from '../../__mocks__'; import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { ActiveField } from './types'; import { SearchUILogic } from './'; @@ -21,7 +23,7 @@ import { SearchUILogic } from './'; describe('SearchUILogic', () => { const { mount } = new LogicMounter(SearchUILogic); const { http } = mockHttpValues; - const { flashAPIErrors, setErrorMessage } = mockFlashMessageHelpers; + const { setErrorMessage } = mockFlashMessageHelpers; const DEFAULT_VALUES = { dataLoading: true, @@ -182,14 +184,9 @@ describe('SearchUILogic', () => { ); }); - it('handles errors', async () => { - http.get.mockReturnValueOnce(Promise.reject('error')); + itShowsServerErrorAsFlashMessage(http.get, () => { mount(); - SearchUILogic.actions.loadFieldData(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/synonyms/synonyms_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/synonyms/synonyms_logic.test.ts index 0ff84ad4cb9cb..7376bc11df79e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/synonyms/synonyms_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/synonyms/synonyms_logic.test.ts @@ -14,6 +14,8 @@ import '../../__mocks__/engine_logic.mock'; import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { SYNONYMS_PAGE_META } from './constants'; import { SynonymsLogic } from './'; @@ -146,14 +148,9 @@ describe('SynonymsLogic', () => { expect(SynonymsLogic.actions.onSynonymsLoad).toHaveBeenCalledWith(MOCK_SYNONYMS_RESPONSE); }); - it('handles errors', async () => { - http.get.mockReturnValueOnce(Promise.reject('error')); + itShowsServerErrorAsFlashMessage(http.get, () => { mount(); - SynonymsLogic.actions.loadSynonyms(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/utils/recursively_fetch_engines/index.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/utils/recursively_fetch_engines/index.test.ts index 555a880d544f4..c03ca8267993a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/utils/recursively_fetch_engines/index.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/utils/recursively_fetch_engines/index.test.ts @@ -5,15 +5,16 @@ * 2.0. */ -import { mockFlashMessageHelpers, mockHttpValues } from '../../../__mocks__/kea_logic'; +import { mockHttpValues } from '../../../__mocks__/kea_logic'; import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { recursivelyFetchEngines } from './'; describe('recursivelyFetchEngines', () => { const { http } = mockHttpValues; - const { flashAPIErrors } = mockFlashMessageHelpers; const MOCK_PAGE_1 = { meta: { @@ -100,12 +101,7 @@ describe('recursivelyFetchEngines', () => { }); }); - it('handles errors', async () => { - http.get.mockReturnValueOnce(Promise.reject('error')); - + itShowsServerErrorAsFlashMessage(http.get, () => { recursivelyFetchEngines({ endpoint: '/error', onComplete: MOCK_CALLBACK }); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/tables/generic_endpoint_inline_editable_table/generic_endpoint_inline_editable_table_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/tables/generic_endpoint_inline_editable_table/generic_endpoint_inline_editable_table_logic.test.ts index 5cd4b5af8f517..a77892a70d525 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/tables/generic_endpoint_inline_editable_table/generic_endpoint_inline_editable_table_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/tables/generic_endpoint_inline_editable_table/generic_endpoint_inline_editable_table_logic.test.ts @@ -13,6 +13,8 @@ import { import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { GenericEndpointInlineEditableTableLogic } from './generic_endpoint_inline_editable_table_logic'; describe('GenericEndpointInlineEditableTableLogic', () => { @@ -119,14 +121,9 @@ describe('GenericEndpointInlineEditableTableLogic', () => { expect(logic.actions.clearLoading).toHaveBeenCalled(); }); - it('handles errors', async () => { - http.post.mockReturnValueOnce(Promise.reject('error')); + itShowsServerErrorAsFlashMessage(http.post, () => { const logic = mountLogic(); - logic.actions.addItem(item, onSuccess); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); @@ -167,14 +164,9 @@ describe('GenericEndpointInlineEditableTableLogic', () => { expect(logic.actions.clearLoading).toHaveBeenCalled(); }); - it('handles errors', async () => { - http.delete.mockReturnValueOnce(Promise.reject('error')); + itShowsServerErrorAsFlashMessage(http.delete, () => { const logic = mountLogic(); - logic.actions.deleteItem(item, onSuccess); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); @@ -221,14 +213,9 @@ describe('GenericEndpointInlineEditableTableLogic', () => { expect(logic.actions.clearLoading).toHaveBeenCalled(); }); - it('handles errors', async () => { - http.put.mockReturnValueOnce(Promise.reject('error')); + itShowsServerErrorAsFlashMessage(http.put, () => { const logic = mountLogic(); - logic.actions.updateItem(item, onSuccess); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('error'); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/test_helpers/error_handling.ts b/x-pack/plugins/enterprise_search/public/applications/test_helpers/error_handling.ts new file mode 100644 index 0000000000000..4f1f4a40aa503 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/test_helpers/error_handling.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mockFlashMessageHelpers } from '../__mocks__/kea_logic'; + +import { nextTick } from '@kbn/test/jest'; +import { HttpHandler } from 'src/core/public'; + +export const itShowsServerErrorAsFlashMessage = (httpMethod: HttpHandler, callback: () => void) => { + const { flashAPIErrors } = mockFlashMessageHelpers; + it('shows any server errors as flash messages', async () => { + (httpMethod as jest.Mock).mockReturnValueOnce(Promise.reject('error')); + callback(); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalledWith('error'); + }); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/test_helpers/index.ts b/x-pack/plugins/enterprise_search/public/applications/test_helpers/index.ts index 35836d5526615..b0705dd7e134b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/test_helpers/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/test_helpers/index.ts @@ -21,3 +21,4 @@ export { // Misc export { expectedAsyncError } from './expected_async_error'; +export { itShowsServerErrorAsFlashMessage } from './error_handling'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_logic.test.ts index 5ff3964b8f83a..da4e9cad9e276 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_logic.test.ts @@ -15,6 +15,8 @@ import { sourceConfigData } from '../../../../__mocks__/content_sources.mock'; import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../../../test_helpers'; + jest.mock('../../../../app_logic', () => ({ AppLogic: { values: { isOrganization: true } }, })); @@ -413,13 +415,8 @@ describe('AddSourceLogic', () => { expect(setSourceConfigDataSpy).toHaveBeenCalledWith(sourceConfigData); }); - it('handles error', async () => { - http.get.mockReturnValue(Promise.reject('this is an error')); - + itShowsServerErrorAsFlashMessage(http.get, () => { AddSourceLogic.actions.getSourceConfigData('github'); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -474,13 +471,8 @@ describe('AddSourceLogic', () => { ); }); - it('handles error', async () => { - http.get.mockReturnValue(Promise.reject('this is an error')); - + itShowsServerErrorAsFlashMessage(http.get, () => { AddSourceLogic.actions.getSourceConnectData('github', successCallback); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -506,13 +498,8 @@ describe('AddSourceLogic', () => { expect(setSourceConnectDataSpy).toHaveBeenCalledWith(sourceConnectData); }); - it('handles error', async () => { - http.get.mockReturnValue(Promise.reject('this is an error')); - + itShowsServerErrorAsFlashMessage(http.get, () => { AddSourceLogic.actions.getSourceReConnectData('github'); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -532,13 +519,8 @@ describe('AddSourceLogic', () => { expect(setPreContentSourceConfigDataSpy).toHaveBeenCalledWith(config); }); - it('handles error', async () => { - http.get.mockReturnValue(Promise.reject('this is an error')); - + itShowsServerErrorAsFlashMessage(http.get, () => { AddSourceLogic.actions.getPreContentSourceConfigData(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -601,13 +583,8 @@ describe('AddSourceLogic', () => { ); }); - it('handles error', async () => { - http.put.mockReturnValue(Promise.reject('this is an error')); - + itShowsServerErrorAsFlashMessage(http.put, () => { AddSourceLogic.actions.saveSourceConfig(true); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.test.ts index 62e305f72365d..81a97c2d19e16 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.test.ts @@ -15,6 +15,8 @@ import { exampleResult } from '../../../../__mocks__/content_sources.mock'; import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../../../test_helpers'; + const contentSource = { id: 'source123' }; jest.mock('../../source_logic', () => ({ SourceLogic: { values: { contentSource } }, @@ -31,7 +33,7 @@ import { DisplaySettingsLogic, defaultSearchResultConfig } from './display_setti describe('DisplaySettingsLogic', () => { const { http } = mockHttpValues; const { navigateToUrl } = mockKibanaValues; - const { clearFlashMessages, flashAPIErrors, flashSuccessToast } = mockFlashMessageHelpers; + const { clearFlashMessages, flashSuccessToast } = mockFlashMessageHelpers; const { mount } = new LogicMounter(DisplaySettingsLogic); const { searchResultConfig, exampleDocuments } = exampleResult; @@ -406,12 +408,8 @@ describe('DisplaySettingsLogic', () => { }); }); - it('handles error', async () => { - http.get.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.get, () => { DisplaySettingsLogic.actions.initializeDisplaySettings(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -434,12 +432,8 @@ describe('DisplaySettingsLogic', () => { }); }); - it('handles error', async () => { - http.post.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.post, () => { DisplaySettingsLogic.actions.setServerData(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_logic.test.ts index af9d85237335c..d284f5c741eb3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_logic.test.ts @@ -29,6 +29,7 @@ Object.defineProperty(global.window, 'scrollTo', { value: spyScrollTo }); import { ADD, UPDATE } from '../../../../../shared/constants/operations'; import { defaultErrorMessage } from '../../../../../shared/flash_messages/handle_api_errors'; import { SchemaType } from '../../../../../shared/schema/types'; +import { itShowsServerErrorAsFlashMessage } from '../../../../../test_helpers'; import { AppLogic } from '../../../../app_logic'; import { @@ -40,8 +41,7 @@ import { SchemaLogic, dataTypeOptions } from './schema_logic'; describe('SchemaLogic', () => { const { http } = mockHttpValues; - const { clearFlashMessages, flashAPIErrors, flashSuccessToast, setErrorMessage } = - mockFlashMessageHelpers; + const { clearFlashMessages, flashSuccessToast, setErrorMessage } = mockFlashMessageHelpers; const { mount } = new LogicMounter(SchemaLogic); const defaultValues = { @@ -224,12 +224,8 @@ describe('SchemaLogic', () => { expect(onInitializeSchemaSpy).toHaveBeenCalledWith(serverResponse); }); - it('handles error', async () => { - http.get.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.get, () => { SchemaLogic.actions.initializeSchema(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -447,12 +443,8 @@ describe('SchemaLogic', () => { expect(onSchemaSetSuccessSpy).toHaveBeenCalledWith(serverResponse); }); - it('handles error', async () => { - http.post.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.post, () => { SchemaLogic.actions.setServerField(schema, UPDATE); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/synchronization/synchronization_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/synchronization/synchronization_logic.test.ts index 25fb256e85f01..0ccfd6aa63ae4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/synchronization/synchronization_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/synchronization/synchronization_logic.test.ts @@ -15,7 +15,7 @@ import { fullContentSources } from '../../../../__mocks__/content_sources.mock'; import { nextTick } from '@kbn/test/jest'; -import { expectedAsyncError } from '../../../../../test_helpers'; +import { itShowsServerErrorAsFlashMessage } from '../../../../../test_helpers'; jest.mock('../../source_logic', () => ({ SourceLogic: { actions: { setContentSource: jest.fn() } }, @@ -34,7 +34,7 @@ import { describe('SynchronizationLogic', () => { const { http } = mockHttpValues; - const { flashAPIErrors, flashSuccessToast } = mockFlashMessageHelpers; + const { flashSuccessToast } = mockFlashMessageHelpers; const { navigateToUrl } = mockKibanaValues; const { mount } = new LogicMounter(SynchronizationLogic); const contentSource = fullContentSources[0]; @@ -328,19 +328,8 @@ describe('SynchronizationLogic', () => { expect(flashSuccessToast).toHaveBeenCalledWith('Source synchronization settings updated.'); }); - it('handles error', async () => { - const error = { - response: { - error: 'this is an error', - status: 400, - }, - }; - const promise = Promise.reject(error); - http.patch.mockReturnValue(promise); + itShowsServerErrorAsFlashMessage(http.patch, () => { SynchronizationLogic.actions.updateServerSettings(body); - await expectedAsyncError(promise); - - expect(flashAPIErrors).toHaveBeenCalledWith(error); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.test.ts index fb88360de5df0..be288ea208858 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.test.ts @@ -20,6 +20,7 @@ import { expectedAsyncError } from '../../../test_helpers'; jest.mock('../../app_logic', () => ({ AppLogic: { values: { isOrganization: true } }, })); +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; import { AppLogic } from '../../app_logic'; import { SourceLogic } from './source_logic'; @@ -235,19 +236,8 @@ describe('SourceLogic', () => { expect(onUpdateSummarySpy).toHaveBeenCalledWith(contentSource.summary); }); - it('handles error', async () => { - const error = { - response: { - error: 'this is an error', - status: 400, - }, - }; - const promise = Promise.reject(error); - http.get.mockReturnValue(promise); + itShowsServerErrorAsFlashMessage(http.get, () => { SourceLogic.actions.initializeFederatedSummary(contentSource.id); - await expectedAsyncError(promise); - - expect(flashAPIErrors).toHaveBeenCalledWith(error); }); }); @@ -295,20 +285,8 @@ describe('SourceLogic', () => { expect(actions.setSearchResults).toHaveBeenCalledWith(searchServerResponse); }); - it('handles error', async () => { - const error = { - response: { - error: 'this is an error', - status: 400, - }, - }; - const promise = Promise.reject(error); - http.post.mockReturnValue(promise); - - await searchContentSourceDocuments({ sourceId: contentSource.id }, mockBreakpoint); - await expectedAsyncError(promise); - - expect(flashAPIErrors).toHaveBeenCalledWith(error); + itShowsServerErrorAsFlashMessage(http.post, () => { + searchContentSourceDocuments({ sourceId: contentSource.id }, mockBreakpoint); }); }); @@ -367,19 +345,8 @@ describe('SourceLogic', () => { expect(onUpdateSourceNameSpy).toHaveBeenCalledWith(contentSource.name); }); - it('handles error', async () => { - const error = { - response: { - error: 'this is an error', - status: 400, - }, - }; - const promise = Promise.reject(error); - http.patch.mockReturnValue(promise); + itShowsServerErrorAsFlashMessage(http.patch, () => { SourceLogic.actions.updateContentSource(contentSource.id, contentSource); - await expectedAsyncError(promise); - - expect(flashAPIErrors).toHaveBeenCalledWith(error); }); }); @@ -413,19 +380,8 @@ describe('SourceLogic', () => { expect(setButtonNotLoadingSpy).toHaveBeenCalled(); }); - it('handles error', async () => { - const error = { - response: { - error: 'this is an error', - status: 400, - }, - }; - const promise = Promise.reject(error); - http.delete.mockReturnValue(promise); + itShowsServerErrorAsFlashMessage(http.delete, () => { SourceLogic.actions.removeContentSource(contentSource.id); - await expectedAsyncError(promise); - - expect(flashAPIErrors).toHaveBeenCalledWith(error); }); }); @@ -441,19 +397,8 @@ describe('SourceLogic', () => { expect(initializeSourceSpy).toHaveBeenCalledWith(contentSource.id); }); - it('handles error', async () => { - const error = { - response: { - error: 'this is an error', - status: 400, - }, - }; - const promise = Promise.reject(error); - http.post.mockReturnValue(promise); + itShowsServerErrorAsFlashMessage(http.post, () => { SourceLogic.actions.initializeSourceSynchronization(contentSource.id); - await expectedAsyncError(promise); - - expect(flashAPIErrors).toHaveBeenCalledWith(error); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.test.ts index 8518485c98b24..f7e41f6512017 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.test.ts @@ -12,11 +12,10 @@ import { } from '../../../__mocks__/kea_logic'; import { configuredSources, contentSources } from '../../__mocks__/content_sources.mock'; -import { expectedAsyncError } from '../../../test_helpers'; - jest.mock('../../app_logic', () => ({ AppLogic: { values: { isOrganization: true } }, })); +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; import { AppLogic } from '../../app_logic'; import { SourcesLogic, fetchSourceStatuses, POLLING_INTERVAL } from './sources_logic'; @@ -185,19 +184,8 @@ describe('SourcesLogic', () => { expect(http.get).toHaveBeenCalledWith('/internal/workplace_search/account/sources'); }); - it('handles error', async () => { - const error = { - response: { - error: 'this is an error', - status: 400, - }, - }; - const promise = Promise.reject(error); - http.get.mockReturnValue(promise); + itShowsServerErrorAsFlashMessage(http.get, () => { SourcesLogic.actions.initializeSources(); - await expectedAsyncError(promise); - - expect(flashAPIErrors).toHaveBeenCalledWith(error); }); it('handles early logic unmount gracefully in org context', async () => { @@ -259,19 +247,8 @@ describe('SourcesLogic', () => { ); }); - it('handles error', async () => { - const error = { - response: { - error: 'this is an error', - status: 400, - }, - }; - const promise = Promise.reject(error); - http.put.mockReturnValue(promise); + itShowsServerErrorAsFlashMessage(http.put, () => { SourcesLogic.actions.setSourceSearchability(id, true); - await expectedAsyncError(promise); - - expect(flashAPIErrors).toHaveBeenCalledWith(error); }); }); @@ -367,19 +344,8 @@ describe('SourcesLogic', () => { expect(http.get).toHaveBeenCalledWith('/internal/workplace_search/account/sources/status'); }); - it('handles error', async () => { - const error = { - response: { - error: 'this is an error', - status: 400, - }, - }; - const promise = Promise.reject(error); - http.get.mockReturnValue(promise); + itShowsServerErrorAsFlashMessage(http.get, () => { fetchSourceStatuses(true, mockBreakpoint); - await expectedAsyncError(promise); - - expect(flashAPIErrors).toHaveBeenCalledWith(error); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_logic.test.ts index 6f811ce364290..3048dcedef26f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_logic.test.ts @@ -16,6 +16,7 @@ import { mockGroupValues } from './__mocks__/group_logic.mock'; import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; import { GROUPS_PATH } from '../../routes'; import { GroupLogic } from './group_logic'; @@ -24,8 +25,7 @@ describe('GroupLogic', () => { const { mount } = new LogicMounter(GroupLogic); const { http } = mockHttpValues; const { navigateToUrl } = mockKibanaValues; - const { clearFlashMessages, flashAPIErrors, flashSuccessToast, setQueuedErrorMessage } = - mockFlashMessageHelpers; + const { clearFlashMessages, flashSuccessToast, setQueuedErrorMessage } = mockFlashMessageHelpers; const group = groups[0]; const sourceIds = ['123', '124']; @@ -222,13 +222,8 @@ describe('GroupLogic', () => { expect(flashSuccessToast).toHaveBeenCalledWith('Group "group" was successfully deleted.'); }); - it('handles error', async () => { - http.delete.mockReturnValue(Promise.reject('this is an error')); - + itShowsServerErrorAsFlashMessage(http.delete, () => { GroupLogic.actions.deleteGroup(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -253,13 +248,8 @@ describe('GroupLogic', () => { ); }); - it('handles error', async () => { - http.put.mockReturnValue(Promise.reject('this is an error')); - + itShowsServerErrorAsFlashMessage(http.put, () => { GroupLogic.actions.updateGroupName(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -284,13 +274,8 @@ describe('GroupLogic', () => { ); }); - it('handles error', async () => { - http.post.mockReturnValue(Promise.reject('this is an error')); - + itShowsServerErrorAsFlashMessage(http.post, () => { GroupLogic.actions.saveGroupSources(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -322,13 +307,8 @@ describe('GroupLogic', () => { expect(onGroupPrioritiesChangedSpy).toHaveBeenCalledWith(group); }); - it('handles error', async () => { - http.put.mockReturnValue(Promise.reject('this is an error')); - + itShowsServerErrorAsFlashMessage(http.put, () => { GroupLogic.actions.saveGroupSourcePrioritization(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.test.ts index c8b725f7131a6..15951a9f8b9ca 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.test.ts @@ -20,6 +20,8 @@ import { nextTick } from '@kbn/test/jest'; import { JSON_HEADER as headers } from '../../../../../common/constants'; import { DEFAULT_META } from '../../../shared/constants'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { GroupsLogic } from './groups_logic'; // We need to mock out the debounced functionality @@ -227,13 +229,8 @@ describe('GroupsLogic', () => { expect(onInitializeGroupsSpy).toHaveBeenCalledWith(groupsResponse); }); - it('handles error', async () => { - http.get.mockReturnValue(Promise.reject('this is an error')); - + itShowsServerErrorAsFlashMessage(http.get, () => { GroupsLogic.actions.initializeGroups(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -310,13 +307,8 @@ describe('GroupsLogic', () => { expect(setGroupUsersSpy).toHaveBeenCalledWith(users); }); - it('handles error', async () => { - http.get.mockReturnValue(Promise.reject('this is an error')); - + itShowsServerErrorAsFlashMessage(http.get, () => { GroupsLogic.actions.fetchGroupUsers('123'); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -336,13 +328,8 @@ describe('GroupsLogic', () => { expect(setNewGroupSpy).toHaveBeenCalledWith(groups[0]); }); - it('handles error', async () => { - http.post.mockReturnValue(Promise.reject('this is an error')); - + itShowsServerErrorAsFlashMessage(http.post, () => { GroupsLogic.actions.saveNewGroup(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.test.ts index 3f5a63275f05d..b70039636bba0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.test.ts @@ -23,6 +23,8 @@ import { } from '../../../shared/role_mapping/__mocks__/roles'; import { ANY_AUTH_PROVIDER } from '../../../shared/role_mapping/constants'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { RoleMappingsLogic } from './role_mappings_logic'; const emptyUser = { username: '', email: '' }; @@ -349,12 +351,8 @@ describe('RoleMappingsLogic', () => { expect(setRoleMappingsSpy).toHaveBeenCalledWith(mappingsServerProps); }); - it('handles error', async () => { - http.post.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.post, () => { RoleMappingsLogic.actions.enableRoleBasedAccess(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -369,12 +367,8 @@ describe('RoleMappingsLogic', () => { expect(setRoleMappingsDataSpy).toHaveBeenCalledWith(mappingsServerProps); }); - it('handles error', async () => { - http.get.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.get, () => { RoleMappingsLogic.actions.initializeRoleMappings(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); it('resets roleMapping state', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security_logic.test.ts index bc45609e9e83d..df9035d57e56b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security_logic.test.ts @@ -5,19 +5,16 @@ * 2.0. */ -import { - LogicMounter, - mockHttpValues, - mockFlashMessageHelpers, -} from '../../../__mocks__/kea_logic'; +import { LogicMounter, mockHttpValues } from '../../../__mocks__/kea_logic'; import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; + import { SecurityLogic } from './security_logic'; describe('SecurityLogic', () => { const { http } = mockHttpValues; - const { flashAPIErrors } = mockFlashMessageHelpers; const { mount } = new LogicMounter(SecurityLogic); beforeEach(() => { @@ -124,15 +121,8 @@ describe('SecurityLogic', () => { expect(setServerPropsSpy).toHaveBeenCalledWith(serverProps); }); - it('handles error', async () => { - http.get.mockReturnValue(Promise.reject('this is an error')); - + itShowsServerErrorAsFlashMessage(http.get, () => { SecurityLogic.actions.initializeSourceRestrictions(); - try { - await nextTick(); - } catch { - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); - } }); }); @@ -150,15 +140,8 @@ describe('SecurityLogic', () => { ); }); - it('handles error', async () => { - http.patch.mockReturnValue(Promise.reject('this is an error')); - + itShowsServerErrorAsFlashMessage(http.patch, () => { SecurityLogic.actions.saveSourceRestrictions(); - try { - await nextTick(); - } catch { - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); - } }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_logic.test.ts index ebb790b59c1fa..d98c9efe04d8c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_logic.test.ts @@ -15,6 +15,7 @@ import { configuredSources, oauthApplication } from '../../__mocks__/content_sou import { nextTick } from '@kbn/test/jest'; +import { itShowsServerErrorAsFlashMessage } from '../../../test_helpers'; import { ORG_UPDATED_MESSAGE, OAUTH_APP_UPDATED_MESSAGE } from '../../constants'; import { SettingsLogic } from './settings_logic'; @@ -22,7 +23,7 @@ import { SettingsLogic } from './settings_logic'; describe('SettingsLogic', () => { const { http } = mockHttpValues; const { navigateToUrl } = mockKibanaValues; - const { clearFlashMessages, flashAPIErrors, flashSuccessToast } = mockFlashMessageHelpers; + const { clearFlashMessages, flashSuccessToast } = mockFlashMessageHelpers; const { mount } = new LogicMounter(SettingsLogic); const ORG_NAME = 'myOrg'; const defaultValues = { @@ -127,12 +128,8 @@ describe('SettingsLogic', () => { expect(setServerPropsSpy).toHaveBeenCalledWith(configuredSources); }); - it('handles error', async () => { - http.get.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.get, () => { SettingsLogic.actions.initializeSettings(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -150,12 +147,8 @@ describe('SettingsLogic', () => { expect(onInitializeConnectorsSpy).toHaveBeenCalledWith(serverProps); }); - it('handles error', async () => { - http.get.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.get, () => { SettingsLogic.actions.initializeConnectors(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -176,12 +169,8 @@ describe('SettingsLogic', () => { expect(setUpdatedNameSpy).toHaveBeenCalledWith({ organizationName: NAME }); }); - it('handles error', async () => { - http.put.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.put, () => { SettingsLogic.actions.updateOrgName(); - - await nextTick(); - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -205,12 +194,8 @@ describe('SettingsLogic', () => { expect(setIconSpy).toHaveBeenCalledWith(ICON); }); - it('handles error', async () => { - http.put.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.put, () => { SettingsLogic.actions.updateOrgIcon(); - - await nextTick(); - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -234,12 +219,8 @@ describe('SettingsLogic', () => { expect(setLogoSpy).toHaveBeenCalledWith(LOGO); }); - it('handles error', async () => { - http.put.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.put, () => { SettingsLogic.actions.updateOrgLogo(); - - await nextTick(); - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -291,12 +272,8 @@ describe('SettingsLogic', () => { expect(flashSuccessToast).toHaveBeenCalledWith(OAUTH_APP_UPDATED_MESSAGE); }); - it('handles error', async () => { - http.put.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.put, () => { SettingsLogic.actions.updateOauthApplication(); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); @@ -313,12 +290,8 @@ describe('SettingsLogic', () => { expect(flashSuccessToast).toHaveBeenCalled(); }); - it('handles error', async () => { - http.delete.mockReturnValue(Promise.reject('this is an error')); + itShowsServerErrorAsFlashMessage(http.delete, () => { SettingsLogic.actions.deleteSourceConfig(SERVICE_TYPE, NAME); - await nextTick(); - - expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); }); }); From 145ce01ea7036fefc59254419e75795e16d48723 Mon Sep 17 00:00:00 2001 From: Matthew Kime Date: Wed, 10 Nov 2021 14:41:01 -0600 Subject: [PATCH 16/51] [docs] Alerting - index patterns => data views (#115613) * [user docs - index patterns] index pattern => data view (#110421) * index patterns => data views * maps docs changes * add alerting docs * Apply suggestions from code review Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> * cleanup Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> --- docs/user/alerting/rule-types/es-query.asciidoc | 2 +- docs/user/alerting/rule-types/geo-rule-types.asciidoc | 10 +++++----- docs/user/alerting/rule-types/index-threshold.asciidoc | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/user/alerting/rule-types/es-query.asciidoc b/docs/user/alerting/rule-types/es-query.asciidoc index 86367a6a2e2c0..e3ce35687260f 100644 --- a/docs/user/alerting/rule-types/es-query.asciidoc +++ b/docs/user/alerting/rule-types/es-query.asciidoc @@ -17,7 +17,7 @@ Define properties to detect the condition. [role="screenshot"] image::user/alerting/images/rule-types-es-query-conditions.png[Five clauses define the condition to detect] -Index:: This clause requires an *index or index pattern* and a *time field* that will be used for the *time window*. +Index:: This clause requires an *index or data view* and a *time field* that will be used for the *time window*. Size:: This clause specifies the number of documents to pass to the configured actions when the the threshold condition is met. {es} query:: This clause specifies the ES DSL query to execute. The number of documents that match this query will be evaluated against the threshold condition. Aggregations are not supported at this time. diff --git a/docs/user/alerting/rule-types/geo-rule-types.asciidoc b/docs/user/alerting/rule-types/geo-rule-types.asciidoc index 244cf90c855a7..454c51ad69860 100644 --- a/docs/user/alerting/rule-types/geo-rule-types.asciidoc +++ b/docs/user/alerting/rule-types/geo-rule-types.asciidoc @@ -10,17 +10,17 @@ In the event that an entity is contained within a boundary, an alert may be gene ==== Requirements To create a Tracking containment rule, the following requirements must be present: -- *Tracks index or index pattern*: An index containing a `geo_point` field, `date` field, +- *Tracks index or data view*: An index containing a `geo_point` field, `date` field, and some form of entity identifier. An entity identifier is a `keyword` or `number` field that consistently identifies the entity to be tracked. The data in this index should be dynamically updating so that there are entity movements to alert upon. -- *Boundaries index or index pattern*: An index containing `geo_shape` data, such as boundary data and bounding box data. +- *Boundaries index or data view*: An index containing `geo_shape` data, such as boundary data and bounding box data. This data is presumed to be static (not updating). Shape data matching the query is harvested once when the rule is created and anytime after when the rule is re-enabled after disablement. By design, current interval entity locations (_current_ is determined by `date` in -the *Tracked index or index pattern*) are queried to determine if they are contained +the *Tracked index or data view*) are queried to determine if they are contained within any monitored boundaries. Entity data should be somewhat "real time", meaning the dates of new documents aren’t older than the current time minus the amount of the interval. If data older than @@ -39,13 +39,13 @@ as well as 2 Kuery bars used to provide additional filtering context for each of [role="screenshot"] image::user/alerting/images/alert-types-tracking-containment-conditions.png[Five clauses define the condition to detect] -Index (entity):: This clause requires an *index or index pattern*, a *time field* that will be used for the *time window*, and a *`geo_point` field* for tracking. +Index (entity):: This clause requires an *index or data view*, a *time field* that will be used for the *time window*, and a *`geo_point` field* for tracking. When entity:: This clause specifies which crossing option to track. The values *Entered*, *Exited*, and *Crossed* can be selected to indicate which crossing conditions should trigger a rule. *Entered* alerts on entry into a boundary, *Exited* alerts on exit from a boundary, and *Crossed* alerts on all boundary crossings whether they be entrances or exits. -Index (Boundary):: This clause requires an *index or index pattern*, a *`geo_shape` field* +Index (Boundary):: This clause requires an *index or data view*, a *`geo_shape` field* identifying boundaries, and an optional *Human-readable boundary name* for better alerting messages. diff --git a/docs/user/alerting/rule-types/index-threshold.asciidoc b/docs/user/alerting/rule-types/index-threshold.asciidoc index 8c45c158414f4..c65b0f66b1b63 100644 --- a/docs/user/alerting/rule-types/index-threshold.asciidoc +++ b/docs/user/alerting/rule-types/index-threshold.asciidoc @@ -17,7 +17,7 @@ Define properties to detect the condition. [role="screenshot"] image::user/alerting/images/rule-types-index-threshold-conditions.png[Five clauses define the condition to detect] -Index:: This clause requires an *index or index pattern* and a *time field* that will be used for the *time window*. +Index:: This clause requires an *index or data view* and a *time field* that will be used for the *time window*. When:: This clause specifies how the value to be compared to the threshold is calculated. The value is calculated by aggregating a numeric field a the *time window*. The aggregation options are: `count`, `average`, `sum`, `min`, and `max`. When using `count` the document count is used, and an aggregation field is not necessary. Over/Grouped Over:: This clause lets you configure whether the aggregation is applied over all documents, or should be split into groups using a grouping field. If grouping is used, an <> will be created for each group when it exceeds the threshold. To limit the number of alerts on high cardinality fields, you must specify the number of groups to check against the threshold. Only the *top* groups are checked. Threshold:: This clause defines a threshold value and a comparison operator (one of `is above`, `is above or equals`, `is below`, `is below or equals`, or `is between`). The result of the aggregation is compared to this threshold. From 3d7209ce7ddfd65c73b1088ecb233a6c5b9f462d Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Wed, 10 Nov 2021 14:05:28 -0700 Subject: [PATCH 17/51] [Reporting] Fix unhandled promise rejection thrown when launching Chromium (#118119) * [Reporting] Fix unhandled promise rejection thrown when launching Chromium * comment correction * simplify * unit test * Update x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts Co-authored-by: Michael Dokolin Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Michael Dokolin --- .../chromium/driver_factory/index.test.ts | 76 +++++++++++++++++++ .../browsers/chromium/driver_factory/index.ts | 46 +++++------ 2 files changed, 97 insertions(+), 25 deletions(-) create mode 100644 x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.test.ts diff --git a/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.test.ts b/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.test.ts new file mode 100644 index 0000000000000..dae692fae8825 --- /dev/null +++ b/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.test.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import puppeteer from 'puppeteer'; +import * as Rx from 'rxjs'; +import { take } from 'rxjs/operators'; +import { HeadlessChromiumDriverFactory } from '.'; +import type { ReportingCore } from '../../..'; +import { + createMockConfigSchema, + createMockLevelLogger, + createMockReportingCore, +} from '../../../test_helpers'; + +jest.mock('puppeteer'); + +const mock = (browserDriverFactory: HeadlessChromiumDriverFactory) => { + browserDriverFactory.getBrowserLogger = jest.fn(() => new Rx.Observable()); + browserDriverFactory.getProcessLogger = jest.fn(() => new Rx.Observable()); + browserDriverFactory.getPageExit = jest.fn(() => new Rx.Observable()); + return browserDriverFactory; +}; + +describe('class HeadlessChromiumDriverFactory', () => { + let reporting: ReportingCore; + const logger = createMockLevelLogger(); + const path = 'path/to/headless_shell'; + + beforeEach(async () => { + (puppeteer as jest.Mocked).launch.mockResolvedValue({ + newPage: jest.fn().mockResolvedValue({ + target: jest.fn(() => ({ + createCDPSession: jest.fn().mockResolvedValue({ + send: jest.fn(), + }), + })), + emulateTimezone: jest.fn(), + setDefaultTimeout: jest.fn(), + }), + close: jest.fn(), + process: jest.fn(), + } as unknown as puppeteer.Browser); + + reporting = await createMockReportingCore( + createMockConfigSchema({ + capture: { + browser: { chromium: { proxy: {} } }, + timeouts: { openUrl: 50000 }, + }, + }) + ); + }); + + it('createPage returns browser driver and process exit observable', async () => { + const factory = mock(new HeadlessChromiumDriverFactory(reporting, path, logger)); + const utils = await factory.createPage({}).pipe(take(1)).toPromise(); + expect(utils).toHaveProperty('driver'); + expect(utils).toHaveProperty('exit$'); + }); + + it('createPage rejects if Puppeteer launch fails', async () => { + (puppeteer as jest.Mocked).launch.mockRejectedValue( + `Puppeteer Launch mock fail.` + ); + const factory = mock(new HeadlessChromiumDriverFactory(reporting, path, logger)); + expect(() => + factory.createPage({}).pipe(take(1)).toPromise() + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Error spawning Chromium browser! Puppeteer Launch mock fail."` + ); + }); +}); diff --git a/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts b/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts index 264e673d2bf74..2aef62f59985b 100644 --- a/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts +++ b/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts @@ -23,7 +23,7 @@ import { LevelLogger } from '../../../lib'; import { safeChildProcess } from '../../safe_child_process'; import { HeadlessChromiumDriver } from '../driver'; import { args } from './args'; -import { getMetrics, Metrics } from './metrics'; +import { getMetrics } from './metrics'; type BrowserConfig = CaptureConfig['browser']['chromium']; @@ -35,7 +35,7 @@ export class HeadlessChromiumDriverFactory { private getChromiumArgs: () => string[]; private core: ReportingCore; - constructor(core: ReportingCore, binaryPath: string, logger: LevelLogger) { + constructor(core: ReportingCore, binaryPath: string, private logger: LevelLogger) { this.core = core; this.binaryPath = binaryPath; const config = core.getConfig(); @@ -62,7 +62,7 @@ export class HeadlessChromiumDriverFactory { */ createPage( { browserTimezone }: { browserTimezone?: string }, - pLogger: LevelLogger + pLogger = this.logger ): Rx.Observable<{ driver: HeadlessChromiumDriver; exit$: Rx.Observable }> { // FIXME: 'create' is deprecated return Rx.Observable.create(async (observer: InnerSubscriber) => { @@ -72,10 +72,7 @@ export class HeadlessChromiumDriverFactory { const chromiumArgs = this.getChromiumArgs(); logger.debug(`Chromium launch args set to: ${chromiumArgs}`); - let browser: puppeteer.Browser; - let page: puppeteer.Page; - let devTools: puppeteer.CDPSession | undefined; - let startMetrics: Metrics | undefined; + let browser: puppeteer.Browser | null = null; try { browser = await puppeteer.launch({ @@ -89,29 +86,28 @@ export class HeadlessChromiumDriverFactory { TZ: browserTimezone, }, }); + } catch (err) { + observer.error(new Error(`Error spawning Chromium browser! ${err}`)); + return; + } - page = await browser.newPage(); - devTools = await page.target().createCDPSession(); + const page = await browser.newPage(); + const devTools = await page.target().createCDPSession(); - await devTools.send('Performance.enable', { timeDomain: 'timeTicks' }); - startMetrics = await devTools.send('Performance.getMetrics'); + await devTools.send('Performance.enable', { timeDomain: 'timeTicks' }); + const startMetrics = await devTools.send('Performance.getMetrics'); - // Log version info for debugging / maintenance - const versionInfo = await devTools.send('Browser.getVersion'); - logger.debug(`Browser version: ${JSON.stringify(versionInfo)}`); + // Log version info for debugging / maintenance + const versionInfo = await devTools.send('Browser.getVersion'); + logger.debug(`Browser version: ${JSON.stringify(versionInfo)}`); - await page.emulateTimezone(browserTimezone); + await page.emulateTimezone(browserTimezone); - // Set the default timeout for all navigation methods to the openUrl timeout (30 seconds) - // All waitFor methods have their own timeout config passed in to them - page.setDefaultTimeout(durationToNumber(this.captureConfig.timeouts.openUrl)); + // Set the default timeout for all navigation methods to the openUrl timeout + // All waitFor methods have their own timeout config passed in to them + page.setDefaultTimeout(durationToNumber(this.captureConfig.timeouts.openUrl)); - logger.debug(`Browser page driver created`); - } catch (err) { - observer.error(new Error(`Error spawning Chromium browser!`)); - observer.error(err); - throw err; - } + logger.debug(`Browser page driver created`); const childProcess = { async kill() { @@ -134,7 +130,7 @@ export class HeadlessChromiumDriverFactory { } try { - await browser.close(); + await browser?.close(); } catch (err) { // do not throw logger.error(err); From baa658f8a7ce1fec67b176b184a61c4fec52fb7f Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 10 Nov 2021 14:29:39 -0700 Subject: [PATCH 18/51] skip suite failing es promotion (#118251) --- x-pack/test/functional/apps/ml/model_management/model_list.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/ml/model_management/model_list.ts b/x-pack/test/functional/apps/ml/model_management/model_list.ts index 955639dbe60a4..aac1ad5b1e50b 100644 --- a/x-pack/test/functional/apps/ml/model_management/model_list.ts +++ b/x-pack/test/functional/apps/ml/model_management/model_list.ts @@ -10,7 +10,8 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const ml = getService('ml'); - describe('trained models', function () { + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/118251 + describe.skip('trained models', function () { before(async () => { await ml.trainedModels.createTestTrainedModels('classification', 15, true); await ml.trainedModels.createTestTrainedModels('regression', 15); From 2cb46839aa36605ce4b1bac9d9a9c7b4461d7d64 Mon Sep 17 00:00:00 2001 From: Michael Dokolin Date: Wed, 10 Nov 2021 22:32:03 +0100 Subject: [PATCH 19/51] [Reporting] Fix timeouts handling in the screenshotting observable handler (#118186) --- .../server/lib/screenshots/observable.test.ts | 2 +- .../server/lib/screenshots/observable.ts | 9 +- .../screenshots/observable_handler.test.ts | 2 +- .../lib/screenshots/observable_handler.ts | 132 ++++++++---------- 4 files changed, 63 insertions(+), 82 deletions(-) diff --git a/x-pack/plugins/reporting/server/lib/screenshots/observable.test.ts b/x-pack/plugins/reporting/server/lib/screenshots/observable.test.ts index 3dc06996f0f04..3071ecb54dc26 100644 --- a/x-pack/plugins/reporting/server/lib/screenshots/observable.test.ts +++ b/x-pack/plugins/reporting/server/lib/screenshots/observable.test.ts @@ -353,7 +353,7 @@ describe('Screenshot Observable Pipeline', () => { }, }, ], - "error": [Error: An error occurred when trying to read the page for visualization panel info: Error: Mock error!], + "error": [Error: The "wait for elements" phase encountered an error: Error: An error occurred when trying to read the page for visualization panel info: Error: Mock error!], "screenshots": Array [ Object { "data": Object { diff --git a/x-pack/plugins/reporting/server/lib/screenshots/observable.ts b/x-pack/plugins/reporting/server/lib/screenshots/observable.ts index 48802eb5e5fbe..d400c423c5e04 100644 --- a/x-pack/plugins/reporting/server/lib/screenshots/observable.ts +++ b/x-pack/plugins/reporting/server/lib/screenshots/observable.ts @@ -58,9 +58,8 @@ export function getScreenshots$( const screen = new ScreenshotObservableHandler(driver, opts, getTimeouts(captureConfig)); return Rx.from(opts.urlsOrUrlLocatorTuples).pipe( - concatMap((urlOrUrlLocatorTuple, index) => { - return Rx.of(1).pipe( - screen.setupPage(index, urlOrUrlLocatorTuple, apmTrans), + concatMap((urlOrUrlLocatorTuple, index) => + screen.setupPage(index, urlOrUrlLocatorTuple, apmTrans).pipe( catchError((err) => { screen.checkPageIsOpen(); // this fails the job if the browser has closed @@ -69,8 +68,8 @@ export function getScreenshots$( }), takeUntil(exit$), screen.getScreenshots() - ); - }), + ) + ), take(opts.urlsOrUrlLocatorTuples.length), toArray() ); diff --git a/x-pack/plugins/reporting/server/lib/screenshots/observable_handler.test.ts b/x-pack/plugins/reporting/server/lib/screenshots/observable_handler.test.ts index 25a8bed370d86..cb0a513992722 100644 --- a/x-pack/plugins/reporting/server/lib/screenshots/observable_handler.test.ts +++ b/x-pack/plugins/reporting/server/lib/screenshots/observable_handler.test.ts @@ -95,7 +95,7 @@ describe('ScreenshotObservableHandler', () => { const testPipeline = () => test$.toPromise(); await expect(testPipeline).rejects.toMatchInlineSnapshot( - `[Error: The "Test Config" phase took longer than 0.2 seconds. You may need to increase "test.config.value": TimeoutError: Timeout has occurred]` + `[Error: The "Test Config" phase took longer than 0.2 seconds. You may need to increase "test.config.value"]` ); }); diff --git a/x-pack/plugins/reporting/server/lib/screenshots/observable_handler.ts b/x-pack/plugins/reporting/server/lib/screenshots/observable_handler.ts index 87c247273ef04..1db313b091025 100644 --- a/x-pack/plugins/reporting/server/lib/screenshots/observable_handler.ts +++ b/x-pack/plugins/reporting/server/lib/screenshots/observable_handler.ts @@ -7,7 +7,7 @@ import apm from 'elastic-apm-node'; import * as Rx from 'rxjs'; -import { catchError, mergeMap, timeout } from 'rxjs/operators'; +import { catchError, mergeMap, switchMapTo, timeoutWith } from 'rxjs/operators'; import { numberToDuration } from '../../../common/schema_utils'; import { UrlOrUrlLocatorTuple } from '../../../common/types'; import { HeadlessChromiumDriver } from '../../browsers'; @@ -33,7 +33,6 @@ export class ScreenshotObservableHandler { private conditionalHeaders: ScreenshotObservableOpts['conditionalHeaders']; private layout: ScreenshotObservableOpts['layout']; private logger: ScreenshotObservableOpts['logger']; - private waitErrorRegistered = false; constructor( private readonly driver: HeadlessChromiumDriver, @@ -50,35 +49,27 @@ export class ScreenshotObservableHandler { */ public waitUntil(phase: PhaseInstance) { const { timeoutValue, label, configValue } = phase; - return (source: Rx.Observable) => { - return source.pipe( - timeout(timeoutValue), - catchError((error: string | Error) => { - if (this.waitErrorRegistered) { - throw error; // do not create a stack of errors within the error - } - - this.logger.error(error); - let throwError = new Error(`The "${label}" phase encountered an error: ${error}`); - - if (error instanceof Rx.TimeoutError) { - throwError = new Error( - `The "${label}" phase took longer than` + - ` ${numberToDuration(timeoutValue).asSeconds()} seconds.` + - ` You may need to increase "${configValue}": ${error}` - ); - } - - this.waitErrorRegistered = true; - this.logger.error(throwError); - throw throwError; - }) + + return (source: Rx.Observable) => + source.pipe( + catchError((error) => { + throw new Error(`The "${label}" phase encountered an error: ${error}`); + }), + timeoutWith( + timeoutValue, + Rx.throwError( + new Error( + `The "${label}" phase took longer than ${numberToDuration( + timeoutValue + ).asSeconds()} seconds. You may need to increase "${configValue}"` + ) + ) + ) ); - }; } private openUrl(index: number, urlOrUrlLocatorTuple: UrlOrUrlLocatorTuple) { - return mergeMap(() => + return Rx.defer(() => openUrl( this.timeouts.openUrl.timeoutValue, this.driver, @@ -87,24 +78,25 @@ export class ScreenshotObservableHandler { this.conditionalHeaders, this.logger ) - ); + ).pipe(this.waitUntil(this.timeouts.openUrl)); } private waitForElements() { const driver = this.driver; const waitTimeout = this.timeouts.waitForElements.timeoutValue; - return (withPageOpen: Rx.Observable) => - withPageOpen.pipe( - mergeMap(() => getNumberOfItems(waitTimeout, driver, this.layout, this.logger)), - mergeMap(async (itemsCount) => { - // set the viewport to the dimentions from the job, to allow elements to flow into the expected layout - const viewport = this.layout.getViewport(itemsCount) || getDefaultViewPort(); - await Promise.all([ - driver.setViewport(viewport, this.logger), - waitForVisualizations(waitTimeout, driver, itemsCount, this.layout, this.logger), - ]); - }) - ); + + return Rx.defer(() => getNumberOfItems(waitTimeout, driver, this.layout, this.logger)).pipe( + mergeMap((itemsCount) => { + // set the viewport to the dimentions from the job, to allow elements to flow into the expected layout + const viewport = this.layout.getViewport(itemsCount) || getDefaultViewPort(); + + return Rx.forkJoin([ + driver.setViewport(viewport, this.logger), + waitForVisualizations(waitTimeout, driver, itemsCount, this.layout, this.logger), + ]); + }), + this.waitUntil(this.timeouts.waitForElements) + ); } private completeRender(apmTrans: apm.Transaction | null) { @@ -112,32 +104,27 @@ export class ScreenshotObservableHandler { const layout = this.layout; const logger = this.logger; - return (withElements: Rx.Observable) => - withElements.pipe( - mergeMap(async () => { - // Waiting till _after_ elements have rendered before injecting our CSS - // allows for them to be displayed properly in many cases - await injectCustomCss(driver, layout, logger); - - const apmPositionElements = apmTrans?.startSpan('position_elements', 'correction'); - // position panel elements for print layout - await layout.positionElements?.(driver, logger); - apmPositionElements?.end(); - - await waitForRenderComplete(this.timeouts.loadDelay, driver, layout, logger); - }), - mergeMap(() => - Promise.all([ - getTimeRange(driver, layout, logger), - getElementPositionAndAttributes(driver, layout, logger), - getRenderErrors(driver, layout, logger), - ]).then(([timeRange, elementsPositionAndAttributes, renderErrors]) => ({ - elementsPositionAndAttributes, - timeRange, - renderErrors, - })) - ) - ); + return Rx.defer(async () => { + // Waiting till _after_ elements have rendered before injecting our CSS + // allows for them to be displayed properly in many cases + await injectCustomCss(driver, layout, logger); + + const apmPositionElements = apmTrans?.startSpan('position_elements', 'correction'); + // position panel elements for print layout + await layout.positionElements?.(driver, logger); + apmPositionElements?.end(); + + await waitForRenderComplete(this.timeouts.loadDelay, driver, layout, logger); + }).pipe( + mergeMap(() => + Rx.forkJoin({ + timeRange: getTimeRange(driver, layout, logger), + elementsPositionAndAttributes: getElementPositionAndAttributes(driver, layout, logger), + renderErrors: getRenderErrors(driver, layout, logger), + }) + ), + this.waitUntil(this.timeouts.renderComplete) + ); } public setupPage( @@ -145,15 +132,10 @@ export class ScreenshotObservableHandler { urlOrUrlLocatorTuple: UrlOrUrlLocatorTuple, apmTrans: apm.Transaction | null ) { - return (initial: Rx.Observable) => - initial.pipe( - this.openUrl(index, urlOrUrlLocatorTuple), - this.waitUntil(this.timeouts.openUrl), - this.waitForElements(), - this.waitUntil(this.timeouts.waitForElements), - this.completeRender(apmTrans), - this.waitUntil(this.timeouts.renderComplete) - ); + return this.openUrl(index, urlOrUrlLocatorTuple).pipe( + switchMapTo(this.waitForElements()), + switchMapTo(this.completeRender(apmTrans)) + ); } public getScreenshots() { From f3a6e6bf5282b97b9be6beec25f4d5de109a46e1 Mon Sep 17 00:00:00 2001 From: Thom Heymann <190132+thomheymann@users.noreply.github.com> Date: Wed, 10 Nov 2021 21:49:54 +0000 Subject: [PATCH 20/51] issue 100570 flaky test 2 (#118043) * Flaky test * add debug screenshots * . * . * . * . --- .../__snapshots__/nav_control_popover.test.tsx.snap | 2 +- .../spaces/public/nav_control/nav_control_popover.tsx | 6 +++--- x-pack/test/accessibility/apps/spaces.ts | 3 +-- x-pack/test/functional/apps/spaces/enter_space.ts | 6 +----- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/spaces/public/nav_control/__snapshots__/nav_control_popover.test.tsx.snap b/x-pack/plugins/spaces/public/nav_control/__snapshots__/nav_control_popover.test.tsx.snap index e02e81e497806..674f5e8b37ca2 100644 --- a/x-pack/plugins/spaces/public/nav_control/__snapshots__/nav_control_popover.test.tsx.snap +++ b/x-pack/plugins/spaces/public/nav_control/__snapshots__/nav_control_popover.test.tsx.snap @@ -9,6 +9,7 @@ exports[`NavControlPopover renders without crashing 1`] = ` aria-expanded={false} aria-haspopup="true" aria-label="loading" + data-test-subj="spacesNavSelector" onClick={[Function]} title="loading" > @@ -18,7 +19,6 @@ exports[`NavControlPopover renders without crashing 1`] = ` } closePopover={[Function]} - data-test-subj="spacesNavSelector" display="inlineBlock" hasArrow={true} id="spcMenuPopover" diff --git a/x-pack/plugins/spaces/public/nav_control/nav_control_popover.tsx b/x-pack/plugins/spaces/public/nav_control/nav_control_popover.tsx index 41a05a38fa305..d4e7ffe510c8f 100644 --- a/x-pack/plugins/spaces/public/nav_control/nav_control_popover.tsx +++ b/x-pack/plugins/spaces/public/nav_control/nav_control_popover.tsx @@ -98,14 +98,13 @@ export class NavControlPopover extends Component { return ( {element} @@ -154,6 +153,7 @@ export class NavControlPopover extends Component { aria-expanded={this.state.showSpaceSelector} aria-haspopup="true" aria-label={linkTitle} + data-test-subj="spacesNavSelector" title={linkTitle} onClick={this.toggleSpaceSelector} > diff --git a/x-pack/test/accessibility/apps/spaces.ts b/x-pack/test/accessibility/apps/spaces.ts index daddb9b24fe03..3dbdc1900ca35 100644 --- a/x-pack/test/accessibility/apps/spaces.ts +++ b/x-pack/test/accessibility/apps/spaces.ts @@ -96,8 +96,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); // test starts with deleting space b so we can get the space selection page instead of logging out in the test - // FLAKY: https://github.com/elastic/kibana/issues/100968 - it.skip('a11y test for space selection page', async () => { + it('a11y test for space selection page', async () => { await PageObjects.spaceSelector.confirmDeletingSpace(); await a11y.testAppSnapshot(); await PageObjects.spaceSelector.clickSpaceCard('default'); diff --git a/x-pack/test/functional/apps/spaces/enter_space.ts b/x-pack/test/functional/apps/spaces/enter_space.ts index 25fdcfda395ce..d58a5c0f19f39 100644 --- a/x-pack/test/functional/apps/spaces/enter_space.ts +++ b/x-pack/test/functional/apps/spaces/enter_space.ts @@ -14,8 +14,7 @@ export default function enterSpaceFunctonalTests({ const esArchiver = getService('esArchiver'); const PageObjects = getPageObjects(['security', 'spaceSelector']); - // Failing: See https://github.com/elastic/kibana/issues/100570 - describe.skip('Enter Space', function () { + describe('Enter Space', function () { this.tags('includeFirefox'); before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/spaces/enter_space'); @@ -50,15 +49,12 @@ export default function enterSpaceFunctonalTests({ }); await PageObjects.spaceSelector.clickSpaceCard(spaceId); - await PageObjects.spaceSelector.expectRoute(spaceId, '/app/canvas'); - await PageObjects.spaceSelector.openSpacesNav(); // change spaces const newSpaceId = 'default'; await PageObjects.spaceSelector.clickSpaceAvatar(newSpaceId); - await PageObjects.spaceSelector.expectHomePage(newSpaceId); }); }); From dc13f4ee9b97186fc153eaf36e5e48b218db27d4 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Wed, 10 Nov 2021 17:42:28 -0500 Subject: [PATCH 21/51] Remove exploratory view reset button. (#118238) (#118095) --- .../series_editor/series_editor.tsx | 27 ++----------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx index afb8baac0eaf3..4d77c04fc7805 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx @@ -7,14 +7,7 @@ import React, { useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { - EuiSpacer, - EuiFormRow, - EuiFlexItem, - EuiFlexGroup, - EuiButtonEmpty, - EuiHorizontalRule, -} from '@elastic/eui'; +import { EuiSpacer, EuiFormRow, EuiFlexItem, EuiFlexGroup, EuiHorizontalRule } from '@elastic/eui'; import { rgba } from 'polished'; import { euiStyled } from './../../../../../../../../src/plugins/kibana_react/common'; import { AppDataType, ReportViewType, BuilderItem } from '../types'; @@ -62,7 +55,7 @@ export const getSeriesToEdit = ({ export const SeriesEditor = React.memo(function () { const [editorItems, setEditorItems] = useState([]); - const { getSeries, allSeries, reportType, removeSeries } = useSeriesStorage(); + const { getSeries, allSeries, reportType } = useSeriesStorage(); const { loading, indexPatterns } = useAppIndexPatternContext(); @@ -120,15 +113,6 @@ export const SeriesEditor = React.memo(function () { setItemIdToExpandedRowMap(itemIdToExpandedRowMapValues); }; - const resetView = () => { - const totalSeries = allSeries.length; - for (let i = totalSeries; i >= 0; i--) { - removeSeries(i); - } - setEditorItems([]); - setItemIdToExpandedRowMap({}); - }; - return (
    @@ -138,13 +122,6 @@ export const SeriesEditor = React.memo(function () { - {reportType && ( - - resetView()} color="text"> - {RESET_LABEL} - - - )} setItemIdToExpandedRowMap({})} /> From fe3272f8352abaab9732c065eaa5283b884fc251 Mon Sep 17 00:00:00 2001 From: Kristof C Date: Wed, 10 Nov 2021 17:45:51 -0600 Subject: [PATCH 22/51] [Cases] [108671] Fix faulty status api call, if selection is same (#118115) * [Cases] [108671] Fix faulty status api call, if selection is same * Add unit test to ensure selecting same status message does not call api Co-authored-by: Kristof-Pierre Cummings Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../case_action_bar/status_context_menu.test.tsx | 11 +++++++++++ .../case_action_bar/status_context_menu.tsx | 6 ++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/cases/public/components/case_action_bar/status_context_menu.test.tsx b/x-pack/plugins/cases/public/components/case_action_bar/status_context_menu.test.tsx index 54cbbc5b6841f..93ecf4df997d2 100644 --- a/x-pack/plugins/cases/public/components/case_action_bar/status_context_menu.test.tsx +++ b/x-pack/plugins/cases/public/components/case_action_bar/status_context_menu.test.tsx @@ -60,4 +60,15 @@ describe('SyncAlertsSwitch', () => { expect(onStatusChanged).toHaveBeenCalledWith('in-progress'); }); + + it('it does not call onStatusChanged if selection is same as current status', async () => { + const wrapper = mount( + + ); + + wrapper.find(`[data-test-subj="case-view-status-dropdown"] button`).simulate('click'); + wrapper.find(`[data-test-subj="case-view-status-dropdown-open"] button`).simulate('click'); + + expect(onStatusChanged).not.toHaveBeenCalled(); + }); }); diff --git a/x-pack/plugins/cases/public/components/case_action_bar/status_context_menu.tsx b/x-pack/plugins/cases/public/components/case_action_bar/status_context_menu.tsx index 603efb253f051..ab86f589bfdd0 100644 --- a/x-pack/plugins/cases/public/components/case_action_bar/status_context_menu.tsx +++ b/x-pack/plugins/cases/public/components/case_action_bar/status_context_menu.tsx @@ -33,9 +33,11 @@ const StatusContextMenuComponent: React.FC = ({ const onContextMenuItemClick = useCallback( (status: CaseStatuses) => { closePopover(); - onStatusChanged(status); + if (currentStatus !== status) { + onStatusChanged(status); + } }, - [closePopover, onStatusChanged] + [closePopover, currentStatus, onStatusChanged] ); const panelItems = useMemo( From f815eaa1d23ec7e3de1622c44b4e792d92a23a23 Mon Sep 17 00:00:00 2001 From: Byron Hulcher Date: Wed, 10 Nov 2021 18:48:49 -0500 Subject: [PATCH 23/51] Fix margins for various pending suggestions callouts (#118208) --- .../components/curations/components/suggestions_callout.tsx | 5 +++-- .../curations/curation/suggested_documents_callout.tsx | 1 + .../components/suggested_curations_callout.tsx | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_callout.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_callout.tsx index 490e6323290f0..ed46a878f0cea 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_callout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_callout.tsx @@ -28,6 +28,7 @@ interface SuggestionsCalloutProps { description: string; buttonTo: string; lastUpdatedTimestamp: string; // ISO string like '2021-10-04T18:53:02.784Z' + style?: React.CSSProperties; } export const SuggestionsCallout: React.FC = ({ @@ -35,6 +36,7 @@ export const SuggestionsCallout: React.FC = ({ description, buttonTo, lastUpdatedTimestamp, + style, }) => { const { pathname } = useLocation(); @@ -49,7 +51,7 @@ export const SuggestionsCallout: React.FC = ({ return ( <> - +

    {description}

    @@ -80,7 +82,6 @@ export const SuggestionsCallout: React.FC = ({
    - ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.tsx index ec296089a1086..cd9b57651c00a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.tsx @@ -35,6 +35,7 @@ export const SuggestedDocumentsCallout: React.FC = () => { return ( { return ( Date: Wed, 10 Nov 2021 19:13:10 -0500 Subject: [PATCH 24/51] [Security Solution][Endpoint][Admin][Policy] Fixes the endpoint version test on policy details (#118124) --- .../apps/endpoint/policy_details.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts index 49206ffb1070e..02c08b1d7a915 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts @@ -309,8 +309,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); it('should show the supported Endpoint version', async () => { - const supportedVersion = await testSubjects.find('policySupportedVersions'); - expect(supportedVersion).to.be('Agent version ' + popupVersionsMap.get('malware')); + expect(await testSubjects.getVisibleText('policySupportedVersions')).to.equal( + 'Agent version ' + popupVersionsMap.get('malware') + ); }); it('should show the custom message text area when the Notify User checkbox is checked', async () => { From 6d951fee695e6e0887f216ddaceefef6894d498b Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Wed, 10 Nov 2021 18:34:50 -0700 Subject: [PATCH 25/51] Sourcerer UI (#117601) --- .../index_pattern_table.tsx | 11 + .../app/home/global_header/index.test.tsx | 121 +++++ .../public/app/home/global_header/index.tsx | 27 +- .../components/case_header_page/index.tsx | 4 +- .../__snapshots__/index.test.tsx.snap | 3 - .../common/components/header_page/index.tsx | 7 - .../common/components/sourcerer/helpers.tsx | 126 +++++ .../components/sourcerer/index.test.tsx | 402 ++++++++++----- .../common/components/sourcerer/index.tsx | 362 +++++++------- .../components/sourcerer/translations.ts | 83 +++- .../sourcerer/use_pick_index_patterns.tsx | 167 +++++++ .../common/containers/sourcerer/index.tsx | 31 +- .../public/common/store/sourcerer/helpers.ts | 28 +- .../detection_engine_header_page/index.tsx | 2 +- .../public/overview/pages/overview.tsx | 3 - .../timeline/eql_tab_content/index.tsx | 7 +- .../timeline/query_tab_content/index.tsx | 7 +- .../search_or_filter/pick_events.test.tsx | 220 --------- .../timeline/search_or_filter/pick_events.tsx | 465 ------------------ .../public/timelines/pages/timelines_page.tsx | 3 +- .../public/ueba/pages/details/index.tsx | 1 - .../translations/translations/ja-JP.json | 3 - .../translations/translations/zh-CN.json | 3 - 23 files changed, 1040 insertions(+), 1046 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/app/home/global_header/index.test.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/sourcerer/helpers.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/sourcerer/use_pick_index_patterns.tsx delete mode 100644 x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/pick_events.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/pick_events.tsx diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx b/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx index 0ad71d9a23cc2..89230ae03a923 100644 --- a/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx @@ -50,6 +50,13 @@ const title = i18n.translate('indexPatternManagement.dataViewTable.title', { defaultMessage: 'Data views', }); +const securityDataView = i18n.translate( + 'indexPatternManagement.indexPatternTable.badge.securityDataViewTitle', + { + defaultMessage: 'Security Data View', + } +); + interface Props extends RouteComponentProps { canSave: boolean; showCreateDialog?: boolean; @@ -116,6 +123,10 @@ export const IndexPatternTable = ({   + {index.id && index.id === 'security-solution' && ( + {securityDataView} + )} + {index.tags && index.tags.map(({ key: tagKey, name: tagName }) => ( {tagName} diff --git a/x-pack/plugins/security_solution/public/app/home/global_header/index.test.tsx b/x-pack/plugins/security_solution/public/app/home/global_header/index.test.tsx new file mode 100644 index 0000000000000..c16e77e9182f2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/app/home/global_header/index.test.tsx @@ -0,0 +1,121 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { render } from '@testing-library/react'; +import { useLocation } from 'react-router-dom'; +import { GlobalHeader } from '.'; +import { SecurityPageName } from '../../../../common/constants'; +import { + createSecuritySolutionStorageMock, + mockGlobalState, + SUB_PLUGINS_REDUCER, + TestProviders, +} from '../../../common/mock'; +import { TimelineId } from '../../../../common/types/timeline'; +import { createStore } from '../../../common/store'; +import { kibanaObservable } from '../../../../../timelines/public/mock'; +import { sourcererPaths } from '../../../common/containers/sourcerer'; + +jest.mock('react-router-dom', () => { + const actual = jest.requireActual('react-router-dom'); + return { ...actual, useLocation: jest.fn().mockReturnValue({ pathname: '' }) }; +}); + +jest.mock('../../../common/lib/kibana', () => { + const originalModule = jest.requireActual('../../../common/lib/kibana'); + return { + ...originalModule, + useKibana: jest + .fn() + .mockReturnValue({ services: { http: { basePath: { prepend: jest.fn() } } } }), + useUiSetting$: jest.fn().mockReturnValue([]), + }; +}); + +jest.mock('react-reverse-portal', () => ({ + InPortal: ({ children }: { children: React.ReactNode }) => <>{children}, + OutPortal: ({ children }: { children: React.ReactNode }) => <>{children}, + createPortalNode: () => ({ unmount: jest.fn() }), +})); + +describe('global header', () => { + const mockSetHeaderActionMenu = jest.fn(); + const state = { + ...mockGlobalState, + timeline: { + ...mockGlobalState.timeline, + timelineById: { + [TimelineId.active]: { + ...mockGlobalState.timeline.timelineById.test, + show: false, + }, + }, + }, + }; + const { storage } = createSecuritySolutionStorageMock(); + const store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + + it('has add data link', () => { + (useLocation as jest.Mock).mockReturnValue([ + { pageName: SecurityPageName.overview, detailName: undefined }, + ]); + const { getByText } = render( + + + + ); + expect(getByText('Add integrations')).toBeInTheDocument(); + }); + + it.each(sourcererPaths)('shows sourcerer on %s page', (pathname) => { + (useLocation as jest.Mock).mockReturnValue({ pathname }); + + const { getByTestId } = render( + + + + ); + expect(getByTestId('sourcerer-trigger')).toBeInTheDocument(); + }); + + it('shows sourcerer on rule details page', () => { + (useLocation as jest.Mock).mockReturnValue({ pathname: sourcererPaths[2] }); + + const { getByTestId } = render( + + + + ); + expect(getByTestId('sourcerer-trigger')).toBeInTheDocument(); + }); + + it('shows no sourcerer if timeline is open', () => { + const mockstate = { + ...mockGlobalState, + timeline: { + ...mockGlobalState.timeline, + timelineById: { + [TimelineId.active]: { + ...mockGlobalState.timeline.timelineById.test, + show: true, + }, + }, + }, + }; + const mockStore = createStore(mockstate, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + + (useLocation as jest.Mock).mockReturnValue({ pathname: sourcererPaths[2] }); + + const { queryByTestId } = render( + + + + ); + + expect(queryByTestId('sourcerer-trigger')).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/app/home/global_header/index.tsx b/x-pack/plugins/security_solution/public/app/home/global_header/index.tsx index 41e441fd4110f..6afcc649da5f3 100644 --- a/x-pack/plugins/security_solution/public/app/home/global_header/index.tsx +++ b/x-pack/plugins/security_solution/public/app/home/global_header/index.tsx @@ -5,14 +5,14 @@ * 2.0. */ import { - EuiHeaderSection, - EuiHeaderLinks, EuiHeaderLink, + EuiHeaderLinks, + EuiHeaderSection, EuiHeaderSectionItem, } from '@elastic/eui'; import React, { useEffect, useMemo } from 'react'; import { useLocation } from 'react-router-dom'; -import { createPortalNode, OutPortal, InPortal } from 'react-reverse-portal'; +import { createPortalNode, InPortal, OutPortal } from 'react-reverse-portal'; import { i18n } from '@kbn/i18n'; import { AppMountParameters } from '../../../../../../../src/core/public'; @@ -21,6 +21,12 @@ import { MlPopover } from '../../../common/components/ml_popover/ml_popover'; import { useKibana } from '../../../common/lib/kibana'; import { ADD_DATA_PATH } from '../../../../common/constants'; import { isDetectionsPath } from '../../../../public/helpers'; +import { Sourcerer } from '../../../common/components/sourcerer'; +import { TimelineId } from '../../../../common/types/timeline'; +import { timelineDefaults } from '../../../timelines/store/timeline/defaults'; +import { timelineSelectors } from '../../../timelines/store/timeline'; +import { useShallowEqualSelector } from '../../../common/hooks/use_selector'; +import { getScopeFromPath, showSourcererByPath } from '../../../common/containers/sourcerer'; const BUTTON_ADD_DATA = i18n.translate('xpack.securitySolution.globalHeader.buttonAddData', { defaultMessage: 'Add integrations', @@ -40,6 +46,16 @@ export const GlobalHeader = React.memo( } = useKibana().services; const { pathname } = useLocation(); + const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); + const showTimeline = useShallowEqualSelector( + (state) => (getTimeline(state, TimelineId.active) ?? timelineDefaults).show + ); + + const sourcererScope = getScopeFromPath(pathname); + const showSourcerer = showSourcererByPath(pathname); + + const href = useMemo(() => prepend(ADD_DATA_PATH), [prepend]); + useEffect(() => { setHeaderActionMenu((element) => { const mount = toMountPoint(); @@ -65,11 +81,14 @@ export const GlobalHeader = React.memo( {BUTTON_ADD_DATA} + {showSourcerer && !showTimeline && ( + + )} diff --git a/x-pack/plugins/security_solution/public/cases/components/case_header_page/index.tsx b/x-pack/plugins/security_solution/public/cases/components/case_header_page/index.tsx index 53bc20af5e491..c1eb11ea5182d 100644 --- a/x-pack/plugins/security_solution/public/cases/components/case_header_page/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/case_header_page/index.tsx @@ -9,8 +9,6 @@ import React from 'react'; import { HeaderPage, HeaderPageProps } from '../../../common/components/header_page'; -const CaseHeaderPageComponent: React.FC = (props) => ( - -); +const CaseHeaderPageComponent: React.FC = (props) => ; export const CaseHeaderPage = React.memo(CaseHeaderPageComponent); diff --git a/x-pack/plugins/security_solution/public/common/components/header_page/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/header_page/__snapshots__/index.test.tsx.snap index d00bd7040c164..9e5b265c187cf 100644 --- a/x-pack/plugins/security_solution/public/common/components/header_page/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/common/components/header_page/__snapshots__/index.test.tsx.snap @@ -33,9 +33,6 @@ exports[`HeaderPage it renders 1`] = ` Test supplement

    - = ({ border, children, draggableArguments, - hideSourcerer = false, isLoading, - sourcererScope = SourcererScopeName.default, subtitle, subtitle2, title, @@ -149,7 +143,6 @@ const HeaderPageComponent: React.FC = ({ {children} )} - {!hideSourcerer && } {/* Manually add a 'padding-bottom' to header */} diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/helpers.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/helpers.tsx new file mode 100644 index 0000000000000..af21a018ee47a --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/helpers.tsx @@ -0,0 +1,126 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiSuperSelectOption, + EuiIcon, + EuiBadge, + EuiButtonEmpty, + EuiFormRow, + EuiFormRowProps, +} from '@elastic/eui'; +import styled from 'styled-components'; + +import { sourcererModel } from '../../store/sourcerer'; + +import * as i18n from './translations'; + +export const FormRow = styled(EuiFormRow)` + display: ${({ $expandAdvancedOptions }) => ($expandAdvancedOptions ? 'flex' : 'none')}; + max-width: none; +`; + +export const StyledFormRow = styled(EuiFormRow)` + max-width: none; +`; + +export const StyledButton = styled(EuiButtonEmpty)` + &:enabled:focus, + &:focus { + background-color: transparent; + } +`; + +export const ResetButton = styled(EuiButtonEmpty)` + width: fit-content; + &:enabled:focus, + &:focus { + background-color: transparent; + } +`; + +export const PopoverContent = styled.div` + width: 600px; +`; + +export const StyledBadge = styled(EuiBadge)` + margin-left: 8px; +`; + +interface GetDataViewSelectOptionsProps { + dataViewId: string; + defaultDataView: sourcererModel.KibanaDataView; + isModified: boolean; + isOnlyDetectionAlerts: boolean; + kibanaDataViews: sourcererModel.KibanaDataView[]; +} + +export const getDataViewSelectOptions = ({ + dataViewId, + defaultDataView, + isModified, + isOnlyDetectionAlerts, + kibanaDataViews, +}: GetDataViewSelectOptionsProps): Array> => + isOnlyDetectionAlerts + ? [ + { + inputDisplay: ( + + {i18n.SIEM_SECURITY_DATA_VIEW_LABEL} + + {i18n.ALERTS_BADGE_TITLE} + + + ), + value: defaultDataView.id, + }, + ] + : kibanaDataViews.map(({ title, id }) => ({ + inputDisplay: + id === defaultDataView.id ? ( + + {i18n.SECURITY_DEFAULT_DATA_VIEW_LABEL} + {isModified && id === dataViewId && ( + {i18n.MODIFIED_BADGE_TITLE} + )} + + ) : ( + + {title} + {isModified && id === dataViewId && ( + {i18n.MODIFIED_BADGE_TITLE} + )} + + ), + value: id, + })); + +interface GetTooltipContent { + isOnlyDetectionAlerts: boolean; + isPopoverOpen: boolean; + selectedPatterns: string[]; + signalIndexName: string | null; +} + +export const getTooltipContent = ({ + isOnlyDetectionAlerts, + isPopoverOpen, + selectedPatterns, + signalIndexName, +}: GetTooltipContent): string | null => { + if (isPopoverOpen || (isOnlyDetectionAlerts && !signalIndexName)) { + return null; + } + return (isOnlyDetectionAlerts ? [signalIndexName] : selectedPatterns).join(', '); +}; + +export const getPatternListWithoutSignals = ( + patternList: string[], + signalIndexName: string | null +): string[] => patternList.filter((p) => p !== signalIndexName); diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx index 1b23d23c5eb62..c2da7e78d64e0 100644 --- a/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx @@ -17,7 +17,7 @@ import { SUB_PLUGINS_REDUCER, TestProviders, } from '../../mock'; -import { createStore, State } from '../../store'; +import { createStore } from '../../store'; import { EuiSuperSelectOption } from '@elastic/eui/src/components/form/super_select/super_select_control'; const mockDispatch = jest.fn(); @@ -45,31 +45,55 @@ const defaultProps = { scope: sourcererModel.SourcererScopeName.default, }; -describe('Sourcerer component', () => { - const state: State = mockGlobalState; - const { id, patternList, title } = state.sourcerer.defaultDataView; - const patternListNoSignals = patternList - .filter((p) => p !== state.sourcerer.signalIndexName) - .sort(); - const checkOptionsAndSelections = (wrapper: ReactWrapper, patterns: string[]) => ({ - availableOptionCount: wrapper.find(`[data-test-subj="sourcerer-combo-option"]`).length, - optionsSelected: patterns.every((pattern) => - wrapper - .find(`[data-test-subj="sourcerer-combo-box"] span[title="${pattern}"]`) - .first() - .exists() - ), - }); +const checkOptionsAndSelections = (wrapper: ReactWrapper, patterns: string[]) => ({ + availableOptionCount: wrapper.find(`[data-test-subj="sourcerer-combo-option"]`).length, + optionsSelected: patterns.every((pattern) => + wrapper.find(`[data-test-subj="sourcerer-combo-box"] span[title="${pattern}"]`).first().exists() + ), +}); +const { id, patternList, title } = mockGlobalState.sourcerer.defaultDataView; +const patternListNoSignals = patternList + .filter((p) => p !== mockGlobalState.sourcerer.signalIndexName) + .sort(); +let store: ReturnType; +describe('Sourcerer component', () => { const { storage } = createSecuritySolutionStorageMock(); - let store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); beforeEach(() => { - store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + store = createStore(mockGlobalState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); jest.clearAllMocks(); jest.restoreAllMocks(); }); + it('renders data view title', () => { + const wrapper = mount( + + + + ); + wrapper.find(`[data-test-subj="sourcerer-trigger"]`).first().simulate('click'); + expect(wrapper.find(`[data-test-subj="sourcerer-title"]`).first().text()).toEqual( + 'Data view selection' + ); + }); + + it('renders a toggle for advanced options', () => { + const testProps = { + ...defaultProps, + showAlertsOnlyCheckbox: true, + }; + const wrapper = mount( + + + + ); + wrapper.find(`[data-test-subj="sourcerer-trigger"]`).first().simulate('click'); + expect( + wrapper.find(`[data-test-subj="sourcerer-advanced-options-toggle"]`).first().text() + ).toEqual('Advanced options'); + }); + it('renders tooltip', () => { const wrapper = mount( @@ -119,25 +143,25 @@ describe('Sourcerer component', () => { it('Removes duplicate options from title', () => { store = createStore( { - ...state, + ...mockGlobalState, sourcerer: { - ...state.sourcerer, + ...mockGlobalState.sourcerer, defaultDataView: { - ...state.sourcerer.defaultDataView, + ...mockGlobalState.sourcerer.defaultDataView, id: '1234', title: 'filebeat-*,auditbeat-*,auditbeat-*,auditbeat-*,auditbeat-*', patternList: ['filebeat-*', 'auditbeat-*'], }, kibanaDataViews: [ { - ...state.sourcerer.defaultDataView, + ...mockGlobalState.sourcerer.defaultDataView, id: '1234', title: 'filebeat-*,auditbeat-*,auditbeat-*,auditbeat-*,auditbeat-*', patternList: ['filebeat-*', 'auditbeat-*'], }, ], sourcererScopes: { - ...state.sourcerer.sourcererScopes, + ...mockGlobalState.sourcerer.sourcererScopes, [SourcererScopeName.default]: { ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.default], loading: false, @@ -170,25 +194,25 @@ describe('Sourcerer component', () => { it('Disables options with no data', () => { store = createStore( { - ...state, + ...mockGlobalState, sourcerer: { - ...state.sourcerer, + ...mockGlobalState.sourcerer, defaultDataView: { - ...state.sourcerer.defaultDataView, + ...mockGlobalState.sourcerer.defaultDataView, id: '1234', title: 'filebeat-*,auditbeat-*,fakebeat-*', patternList: ['filebeat-*', 'auditbeat-*'], }, kibanaDataViews: [ { - ...state.sourcerer.defaultDataView, + ...mockGlobalState.sourcerer.defaultDataView, id: '1234', title: 'filebeat-*,auditbeat-*,fakebeat-*', patternList: ['filebeat-*', 'auditbeat-*'], }, ], sourcererScopes: { - ...state.sourcerer.sourcererScopes, + ...mockGlobalState.sourcerer.sourcererScopes, [SourcererScopeName.default]: { ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.default], loading: false, @@ -225,15 +249,15 @@ describe('Sourcerer component', () => { sourcerer: { ...mockGlobalState.sourcerer, kibanaDataViews: [ - state.sourcerer.defaultDataView, + mockGlobalState.sourcerer.defaultDataView, { - ...state.sourcerer.defaultDataView, + ...mockGlobalState.sourcerer.defaultDataView, id: '1234', title: 'auditbeat-*', patternList: ['auditbeat-*'], }, { - ...state.sourcerer.defaultDataView, + ...mockGlobalState.sourcerer.defaultDataView, id: '12347', title: 'packetbeat-*', patternList: ['packetbeat-*'], @@ -244,9 +268,8 @@ describe('Sourcerer component', () => { [SourcererScopeName.default]: { ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.default], loading: false, - patternList, selectedDataViewId: id, - selectedPatterns: patternList.slice(0, 2), + selectedPatterns: patternListNoSignals.slice(0, 2), }, }, }, @@ -260,7 +283,7 @@ describe('Sourcerer component', () => { ); wrapper.find(`[data-test-subj="sourcerer-trigger"]`).first().simulate('click'); wrapper.find(`[data-test-subj="comboBoxInput"]`).first().simulate('click'); - expect(checkOptionsAndSelections(wrapper, patternList.slice(0, 2))).toEqual({ + expect(checkOptionsAndSelections(wrapper, patternListNoSignals.slice(0, 2))).toEqual({ // should hide signal index availableOptionCount: title.split(',').length - 3, optionsSelected: true, @@ -272,15 +295,15 @@ describe('Sourcerer component', () => { sourcerer: { ...mockGlobalState.sourcerer, kibanaDataViews: [ - state.sourcerer.defaultDataView, + mockGlobalState.sourcerer.defaultDataView, { - ...state.sourcerer.defaultDataView, + ...mockGlobalState.sourcerer.defaultDataView, id: '1234', title: 'auditbeat-*', patternList: ['auditbeat-*'], }, { - ...state.sourcerer.defaultDataView, + ...mockGlobalState.sourcerer.defaultDataView, id: '12347', title: 'packetbeat-*', patternList: ['packetbeat-*'], @@ -305,7 +328,7 @@ describe('Sourcerer component', () => { ); - wrapper.find(`[data-test-subj="sourcerer-trigger"]`).first().simulate('click'); + wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).first().simulate('click'); wrapper.find(`[data-test-subj="comboBoxInput"]`).first().simulate('click'); expect(checkOptionsAndSelections(wrapper, patternList.slice(0, 2))).toEqual({ // should show every option except fakebeat-* @@ -316,25 +339,25 @@ describe('Sourcerer component', () => { it('onSave dispatches setSelectedDataView', async () => { store = createStore( { - ...state, + ...mockGlobalState, sourcerer: { - ...state.sourcerer, + ...mockGlobalState.sourcerer, kibanaDataViews: [ - state.sourcerer.defaultDataView, + mockGlobalState.sourcerer.defaultDataView, { - ...state.sourcerer.defaultDataView, + ...mockGlobalState.sourcerer.defaultDataView, id: '1234', title: 'filebeat-*', patternList: ['filebeat-*'], }, ], sourcererScopes: { - ...state.sourcerer.sourcererScopes, + ...mockGlobalState.sourcerer.sourcererScopes, [SourcererScopeName.default]: { ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.default], loading: false, selectedDataViewId: id, - selectedPatterns: patternList.slice(0, 2), + selectedPatterns: patternListNoSignals.slice(0, 2), }, }, }, @@ -350,13 +373,12 @@ describe('Sourcerer component', () => { ); wrapper.find(`[data-test-subj="sourcerer-trigger"]`).first().simulate('click'); wrapper.find(`[data-test-subj="comboBoxInput"]`).first().simulate('click'); - expect(checkOptionsAndSelections(wrapper, patternList.slice(0, 2))).toEqual({ + expect(checkOptionsAndSelections(wrapper, patternListNoSignals.slice(0, 2))).toEqual({ availableOptionCount: title.split(',').length - 3, optionsSelected: true, }); - wrapper.find(`[data-test-subj="sourcerer-combo-option"]`).first().simulate('click'); - expect(checkOptionsAndSelections(wrapper, patternList.slice(0, 3))).toEqual({ + expect(checkOptionsAndSelections(wrapper, patternListNoSignals.slice(0, 3))).toEqual({ availableOptionCount: title.split(',').length - 4, optionsSelected: true, }); @@ -367,7 +389,7 @@ describe('Sourcerer component', () => { sourcererActions.setSelectedDataView({ id: SourcererScopeName.default, selectedDataViewId: id, - selectedPatterns: patternList.slice(0, 3), + selectedPatterns: patternListNoSignals.slice(0, 3), }) ); }); @@ -387,7 +409,7 @@ describe('Sourcerer component', () => { wrapper .find( - `[data-test-subj="sourcerer-combo-box"] [title="${patternList[0]}"] button.euiBadge__iconButton` + `[data-test-subj="sourcerer-combo-box"] [title="${patternListNoSignals[0]}"] button.euiBadge__iconButton` ) .first() .simulate('click'); @@ -407,13 +429,13 @@ describe('Sourcerer component', () => { it('disables saving when no index patterns are selected', () => { store = createStore( { - ...state, + ...mockGlobalState, sourcerer: { - ...state.sourcerer, + ...mockGlobalState.sourcerer, kibanaDataViews: [ - state.sourcerer.defaultDataView, + mockGlobalState.sourcerer.defaultDataView, { - ...state.sourcerer.defaultDataView, + ...mockGlobalState.sourcerer.defaultDataView, id: '1234', title: 'auditbeat-*', patternList: ['auditbeat-*'], @@ -434,72 +456,21 @@ describe('Sourcerer component', () => { wrapper.find('[data-test-subj="comboBoxClearButton"]').first().simulate('click'); expect(wrapper.find('[data-test-subj="sourcerer-save"]').first().prop('disabled')).toBeTruthy(); }); - it('Selects a different index pattern', async () => { - const state2 = { - ...mockGlobalState, - sourcerer: { - ...mockGlobalState.sourcerer, - kibanaDataViews: [ - state.sourcerer.defaultDataView, - { - ...state.sourcerer.defaultDataView, - id: '1234', - title: 'fakebeat-*,neatbeat-*', - patternList: ['fakebeat-*'], - }, - ], - sourcererScopes: { - ...mockGlobalState.sourcerer.sourcererScopes, - [SourcererScopeName.default]: { - ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.default], - loading: false, - patternList, - selectedDataViewId: id, - selectedPatterns: patternList.slice(0, 2), - }, - }, - }, - }; - - store = createStore(state2, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - const wrapper = mount( - - - - ); - wrapper.find(`[data-test-subj="sourcerer-trigger"]`).first().simulate('click'); - wrapper.find(`button[data-test-subj="sourcerer-select"]`).first().simulate('click'); - - wrapper.find(`[data-test-subj="dataView-option-super"]`).first().simulate('click'); - expect(checkOptionsAndSelections(wrapper, ['fakebeat-*'])).toEqual({ - availableOptionCount: 0, - optionsSelected: true, - }); - wrapper.find(`[data-test-subj="sourcerer-save"]`).first().simulate('click'); - - expect(mockDispatch).toHaveBeenCalledWith( - sourcererActions.setSelectedDataView({ - id: SourcererScopeName.default, - selectedDataViewId: '1234', - selectedPatterns: ['fakebeat-*'], - }) - ); - }); it('Does display signals index on timeline sourcerer', () => { const state2 = { ...mockGlobalState, sourcerer: { ...mockGlobalState.sourcerer, kibanaDataViews: [ - state.sourcerer.defaultDataView, + mockGlobalState.sourcerer.defaultDataView, { - ...state.sourcerer.defaultDataView, + ...mockGlobalState.sourcerer.defaultDataView, id: '1234', title: 'auditbeat-*', patternList: ['auditbeat-*'], }, { - ...state.sourcerer.defaultDataView, + ...mockGlobalState.sourcerer.defaultDataView, id: '12347', title: 'packetbeat-*', patternList: ['packetbeat-*'], @@ -510,9 +481,8 @@ describe('Sourcerer component', () => { [SourcererScopeName.timeline]: { ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.timeline], loading: false, - patternList, selectedDataViewId: id, - selectedPatterns: patternList.slice(0, 2), + selectedPatterns: patternListNoSignals.slice(0, 2), }, }, }, @@ -524,9 +494,9 @@ describe('Sourcerer component', () => { ); - wrapper.find(`[data-test-subj="sourcerer-trigger"]`).first().simulate('click'); + wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).first().simulate('click'); wrapper.find(`[data-test-subj="comboBoxToggleListButton"]`).first().simulate('click'); - expect(wrapper.find(`[data-test-subj="sourcerer-combo-option"]`).at(6).text()).toEqual( + expect(wrapper.find(`[data-test-subj="sourcerer-combo-option"]`).at(0).text()).toEqual( mockGlobalState.sourcerer.signalIndexName ); }); @@ -536,15 +506,15 @@ describe('Sourcerer component', () => { sourcerer: { ...mockGlobalState.sourcerer, kibanaDataViews: [ - state.sourcerer.defaultDataView, + mockGlobalState.sourcerer.defaultDataView, { - ...state.sourcerer.defaultDataView, + ...mockGlobalState.sourcerer.defaultDataView, id: '1234', title: 'auditbeat-*', patternList: ['auditbeat-*'], }, { - ...state.sourcerer.defaultDataView, + ...mockGlobalState.sourcerer.defaultDataView, id: '12347', title: 'packetbeat-*', patternList: ['packetbeat-*'], @@ -555,9 +525,8 @@ describe('Sourcerer component', () => { [SourcererScopeName.default]: { ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.default], loading: false, - patternList, selectedDataViewId: id, - selectedPatterns: patternList.slice(0, 2), + selectedPatterns: patternListNoSignals.slice(0, 2), }, }, }, @@ -581,3 +550,204 @@ describe('Sourcerer component', () => { ).toBeFalsy(); }); }); + +describe('sourcerer on alerts page or rules details page', () => { + let wrapper: ReactWrapper; + const { storage } = createSecuritySolutionStorageMock(); + store = createStore(mockGlobalState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + const testProps = { + scope: sourcererModel.SourcererScopeName.detections, + }; + + beforeAll(() => { + wrapper = mount( + + + + ); + wrapper.find(`[data-test-subj="sourcerer-trigger"]`).first().simulate('click'); + wrapper.find(`[data-test-subj="sourcerer-advanced-options-toggle"]`).first().simulate('click'); + }); + + it('renders an alerts badge in sourcerer button', () => { + expect(wrapper.find(`[data-test-subj="sourcerer-alerts-badge"]`).first().text()).toEqual( + 'Alerts' + ); + }); + + it('renders a callout', () => { + expect(wrapper.find(`[data-test-subj="sourcerer-callout"]`).first().text()).toEqual( + 'Data view cannot be modified on this page' + ); + }); + + it('disable data view selector', () => { + expect( + wrapper.find(`[data-test-subj="sourcerer-select"]`).first().prop('disabled') + ).toBeTruthy(); + }); + + it('data view selector is default to Security Data View', () => { + expect( + wrapper.find(`[data-test-subj="sourcerer-select"]`).first().prop('valueOfSelected') + ).toEqual('security-solution'); + }); + + it('renders an alert badge in data view selector', () => { + expect(wrapper.find(`[data-test-subj="security-alerts-option-badge"]`).first().text()).toEqual( + 'Alerts' + ); + }); + + it('disable index pattern selector', () => { + expect( + wrapper.find(`[data-test-subj="sourcerer-combo-box"]`).first().prop('disabled') + ).toBeTruthy(); + }); + + it('shows signal index as index pattern option', () => { + expect(wrapper.find(`[data-test-subj="sourcerer-combo-box"]`).first().prop('options')).toEqual([ + { disabled: false, label: '.siem-signals-spacename', value: '.siem-signals-spacename' }, + ]); + }); + + it('does not render reset button', () => { + expect(wrapper.find(`[data-test-subj="sourcerer-reset"]`).exists()).toBeFalsy(); + }); + + it('does not render save button', () => { + expect(wrapper.find(`[data-test-subj="sourcerer-save"]`).exists()).toBeFalsy(); + }); +}); + +describe('timeline sourcerer', () => { + let wrapper: ReactWrapper; + const { storage } = createSecuritySolutionStorageMock(); + store = createStore(mockGlobalState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + const testProps = { + scope: sourcererModel.SourcererScopeName.timeline, + }; + + beforeAll(() => { + wrapper = mount( + + + + ); + wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).first().simulate('click'); + wrapper + .find( + `[data-test-subj="timeline-sourcerer-popover"] [data-test-subj="sourcerer-advanced-options-toggle"]` + ) + .first() + .simulate('click'); + }); + + it('renders "alerts only" checkbox', () => { + wrapper + .find( + `[data-test-subj="timeline-sourcerer-popover"] [data-test-subj="sourcerer-alert-only-checkbox"]` + ) + .first() + .simulate('click'); + expect(wrapper.find(`[data-test-subj="sourcerer-alert-only-checkbox"]`).first().text()).toEqual( + 'Show only detection alerts' + ); + }); + + it('data view selector is enabled', () => { + expect( + wrapper + .find(`[data-test-subj="timeline-sourcerer-popover"] [data-test-subj="sourcerer-select"]`) + .first() + .prop('disabled') + ).toBeFalsy(); + }); + + it('data view selector is default to Security Default Data View', () => { + expect( + wrapper + .find(`[data-test-subj="timeline-sourcerer-popover"] [data-test-subj="sourcerer-select"]`) + .first() + .prop('valueOfSelected') + ).toEqual('security-solution'); + }); + + it('index pattern selector is enabled', () => { + expect( + wrapper + .find( + `[data-test-subj="timeline-sourcerer-popover"] [data-test-subj="sourcerer-combo-box"]` + ) + .first() + .prop('disabled') + ).toBeFalsy(); + }); + + it('render reset button', () => { + expect(wrapper.find(`[data-test-subj="sourcerer-reset"]`).exists()).toBeTruthy(); + }); + + it('render save button', () => { + expect(wrapper.find(`[data-test-subj="sourcerer-save"]`).exists()).toBeTruthy(); + }); +}); + +describe('Sourcerer integration tests', () => { + const state = { + ...mockGlobalState, + sourcerer: { + ...mockGlobalState.sourcerer, + kibanaDataViews: [ + mockGlobalState.sourcerer.defaultDataView, + { + ...mockGlobalState.sourcerer.defaultDataView, + id: '1234', + title: 'fakebeat-*,neatbeat-*', + patternList: ['fakebeat-*'], + }, + ], + sourcererScopes: { + ...mockGlobalState.sourcerer.sourcererScopes, + [SourcererScopeName.default]: { + ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.default], + loading: false, + selectedDataViewId: id, + selectedPatterns: patternListNoSignals.slice(0, 2), + }, + }, + }, + }; + + const { storage } = createSecuritySolutionStorageMock(); + + beforeEach(() => { + store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + jest.clearAllMocks(); + jest.restoreAllMocks(); + }); + it('Selects a different index pattern', async () => { + const wrapper = mount( + + + + ); + wrapper.find(`[data-test-subj="sourcerer-trigger"]`).first().simulate('click'); + wrapper.find(`button[data-test-subj="sourcerer-select"]`).first().simulate('click'); + + wrapper.find(`[data-test-subj="dataView-option-super"]`).first().simulate('click'); + expect(checkOptionsAndSelections(wrapper, ['fakebeat-*'])).toEqual({ + availableOptionCount: 0, + optionsSelected: true, + }); + wrapper.find(`[data-test-subj="sourcerer-save"]`).first().simulate('click'); + + expect(mockDispatch).toHaveBeenCalledWith( + sourcererActions.setSelectedDataView({ + id: SourcererScopeName.default, + selectedDataViewId: '1234', + selectedPatterns: ['fakebeat-*'], + }) + ); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/index.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/index.tsx index 6f32282c53040..6f223cbb4aa30 100644 --- a/x-pack/plugins/security_solution/public/common/components/sourcerer/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/index.tsx @@ -7,48 +7,52 @@ import { EuiButton, - EuiButtonEmpty, + EuiCallOut, + EuiCheckbox, EuiComboBox, - EuiComboBoxOptionOption, EuiFlexGroup, EuiFlexItem, - EuiIcon, + EuiForm, EuiPopover, EuiPopoverTitle, EuiSpacer, EuiSuperSelect, - EuiText, EuiToolTip, } from '@elastic/eui'; import deepEqual from 'fast-deep-equal'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useDispatch } from 'react-redux'; -import styled from 'styled-components'; import * as i18n from './translations'; import { sourcererActions, sourcererModel, sourcererSelectors } from '../../store/sourcerer'; -import { getScopePatternListSelection } from '../../store/sourcerer/helpers'; import { useDeepEqualSelector } from '../../hooks/use_selector'; import { SourcererScopeName } from '../../store/sourcerer/model'; +import { usePickIndexPatterns } from './use_pick_index_patterns'; +import { + FormRow, + getDataViewSelectOptions, + getTooltipContent, + PopoverContent, + ResetButton, + StyledBadge, + StyledButton, + StyledFormRow, +} from './helpers'; -const PopoverContent = styled.div` - width: 600px; -`; - -const ResetButton = styled(EuiButtonEmpty)` - width: fit-content; -`; interface SourcererComponentProps { scope: sourcererModel.SourcererScopeName; } -const getPatternListWithoutSignals = ( - patternList: string[], - signalIndexName: string | null -): string[] => patternList.filter((p) => p !== signalIndexName); - export const Sourcerer = React.memo(({ scope: scopeId }) => { const dispatch = useDispatch(); + const isDetectionsSourcerer = scopeId === SourcererScopeName.detections; + const isTimelineSourcerer = scopeId === SourcererScopeName.timeline; + + const [isOnlyDetectionAlertsChecked, setIsOnlyDetectionAlertsChecked] = useState(false); + + const isOnlyDetectionAlerts: boolean = + isDetectionsSourcerer || (isTimelineSourcerer && isOnlyDetectionAlertsChecked); + const sourcererScopeSelector = useMemo(() => sourcererSelectors.getSourcererScopeSelector(), []); const { defaultDataView, @@ -58,55 +62,39 @@ export const Sourcerer = React.memo(({ scope: scopeId } } = useDeepEqualSelector((state) => sourcererScopeSelector(state, scopeId)); const [isPopoverOpen, setPopoverIsOpen] = useState(false); - const [dataViewId, setDataViewId] = useState(selectedDataViewId ?? defaultDataView.id); - const { patternList, selectablePatterns } = useMemo(() => { - const theDataView = kibanaDataViews.find((dataView) => dataView.id === dataViewId); - return theDataView != null - ? scopeId === SourcererScopeName.default - ? { - patternList: getPatternListWithoutSignals( - theDataView.title - .split(',') - // remove duplicates patterns from selector - .filter((pattern, i, self) => self.indexOf(pattern) === i), - signalIndexName - ), - selectablePatterns: getPatternListWithoutSignals( - theDataView.patternList, - signalIndexName - ), - } - : { - patternList: theDataView.title - .split(',') - // remove duplicates patterns from selector - .filter((pattern, i, self) => self.indexOf(pattern) === i), - selectablePatterns: theDataView.patternList, - } - : { patternList: [], selectablePatterns: [] }; - }, [kibanaDataViews, scopeId, signalIndexName, dataViewId]); - - const selectableOptions = useMemo( - () => - patternList.map((indexName) => ({ - label: indexName, - value: indexName, - disabled: !selectablePatterns.includes(indexName), - })), - [selectablePatterns, patternList] - ); - - const [selectedOptions, setSelectedOptions] = useState>>( - selectedPatterns.map((indexName) => ({ - label: indexName, - value: indexName, - })) + const { + isModified, + onChangeCombo, + renderOption, + selectableOptions, + selectedOptions, + setIndexPatternsByDataView, + } = usePickIndexPatterns({ + dataViewId, + defaultDataViewId: defaultDataView.id, + isOnlyDetectionAlerts, + kibanaDataViews, + scopeId, + selectedPatterns, + signalIndexName, + }); + const onCheckboxChanged = useCallback( + (e) => { + setIsOnlyDetectionAlertsChecked(e.target.checked); + setDataViewId(defaultDataView.id); + setIndexPatternsByDataView(defaultDataView.id, e.target.checked); + }, + [defaultDataView.id, setIndexPatternsByDataView] ); const isSavingDisabled = useMemo(() => selectedOptions.length === 0, [selectedOptions]); + const [expandAdvancedOptions, setExpandAdvancedOptions] = useState(false); - const setPopoverIsOpenCb = useCallback(() => setPopoverIsOpen((prevState) => !prevState), []); + const setPopoverIsOpenCb = useCallback(() => { + setPopoverIsOpen((prevState) => !prevState); + setExpandAdvancedOptions(false); // we always want setExpandAdvancedOptions collapsed by default when popover opened + }, []); const onChangeDataView = useCallback( (newSelectedDataView: string, newSelectedPatterns: string[]) => { dispatch( @@ -120,90 +108,64 @@ export const Sourcerer = React.memo(({ scope: scopeId } [dispatch, scopeId] ); - const renderOption = useCallback( - ({ value }) => {value}, - [] - ); - - const onChangeCombo = useCallback((newSelectedOptions) => { - setSelectedOptions(newSelectedOptions); - }, []); - const onChangeSuper = useCallback( (newSelectedOption) => { setDataViewId(newSelectedOption); - setSelectedOptions( - getScopePatternListSelection( - kibanaDataViews.find((dataView) => dataView.id === newSelectedOption), - scopeId, - signalIndexName, - newSelectedOption === defaultDataView.id - ).map((indexSelected: string) => ({ - label: indexSelected, - value: indexSelected, - })) - ); + setIndexPatternsByDataView(newSelectedOption); }, - [defaultDataView.id, kibanaDataViews, scopeId, signalIndexName] + [setIndexPatternsByDataView] ); const resetDataSources = useCallback(() => { setDataViewId(defaultDataView.id); - setSelectedOptions( - getScopePatternListSelection(defaultDataView, scopeId, signalIndexName, true).map( - (indexSelected: string) => ({ - label: indexSelected, - value: indexSelected, - }) - ) - ); - }, [defaultDataView, scopeId, signalIndexName]); + setIndexPatternsByDataView(defaultDataView.id); + setIsOnlyDetectionAlertsChecked(false); + }, [defaultDataView.id, setIndexPatternsByDataView]); const handleSaveIndices = useCallback(() => { - onChangeDataView( - dataViewId, - selectedOptions.map((so) => so.label) - ); + const patterns = selectedOptions.map((so) => so.label); + onChangeDataView(dataViewId, patterns); setPopoverIsOpen(false); }, [onChangeDataView, dataViewId, selectedOptions]); const handleClosePopOver = useCallback(() => { setPopoverIsOpen(false); + setExpandAdvancedOptions(false); }, []); const trigger = useMemo( () => ( - - {i18n.SOURCERER} - + {i18n.DATA_VIEW} + {isModified === 'modified' && {i18n.MODIFIED_BADGE_TITLE}} + {isModified === 'alerts' && ( + + {i18n.ALERTS_BADGE_TITLE} + + )} + ), - [setPopoverIsOpenCb, loading] + [isTimelineSourcerer, loading, setPopoverIsOpenCb, isModified] ); const dataViewSelectOptions = useMemo( () => - kibanaDataViews.map(({ title, id }) => ({ - inputDisplay: - id === defaultDataView.id ? ( - - {i18n.SIEM_DATA_VIEW_LABEL} - - ) : ( - - {title} - - ), - value: id, - })), - [defaultDataView.id, kibanaDataViews] + getDataViewSelectOptions({ + dataViewId, + defaultDataView, + isModified: isModified === 'modified', + isOnlyDetectionAlerts, + kibanaDataViews, + }), + [dataViewId, defaultDataView, isModified, isOnlyDetectionAlerts, kibanaDataViews] ); useEffect(() => { @@ -213,18 +175,16 @@ export const Sourcerer = React.memo(({ scope: scopeId } : prevSelectedOption ); }, [selectedDataViewId]); - useEffect(() => { - setSelectedOptions( - selectedPatterns.map((indexName) => ({ - label: indexName, - value: indexName, - })) - ); - }, [selectedPatterns]); const tooltipContent = useMemo( - () => (isPopoverOpen ? null : selectedPatterns.join(', ')), - [selectedPatterns, isPopoverOpen] + () => + getTooltipContent({ + isOnlyDetectionAlerts, + isPopoverOpen, + selectedPatterns, + signalIndexName, + }), + [isPopoverOpen, isOnlyDetectionAlerts, signalIndexName, selectedPatterns] ); const buttonWithTooptip = useMemo(() => { @@ -237,67 +197,117 @@ export const Sourcerer = React.memo(({ scope: scopeId } ); }, [trigger, tooltipContent]); + const onExpandAdvancedOptionsClicked = useCallback(() => { + setExpandAdvancedOptions((prevState) => !prevState); + }, []); + return ( - - <>{i18n.SELECT_INDEX_PATTERNS} + + <>{i18n.SELECT_DATA_VIEW} + {isOnlyDetectionAlerts && ( + + )} - {i18n.INDEX_PATTERNS_SELECTION_LABEL} - - - - - - - - - {i18n.INDEX_PATTERNS_RESET} - - - - + {isTimelineSourcerer && ( + + + + )} + + + - {i18n.SAVE_INDEX_PATTERNS} - - - + onChange={onChangeSuper} + options={dataViewSelectOptions} + placeholder={i18n.PICK_INDEX_PATTERNS} + valueOfSelected={dataViewId} + /> + + + + + + {i18n.INDEX_PATTERNS_ADVANCED_OPTIONS_TITLE} + + {expandAdvancedOptions && } + + + + + {!isDetectionsSourcerer && ( + + + + + {i18n.INDEX_PATTERNS_RESET} + + + + + {i18n.SAVE_INDEX_PATTERNS} + + + + + )} + + ); diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/translations.ts b/x-pack/plugins/security_solution/public/common/components/sourcerer/translations.ts index 03fdc5d191719..fcf465ebfc9ef 100644 --- a/x-pack/plugins/security_solution/public/common/components/sourcerer/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/translations.ts @@ -7,29 +7,85 @@ import { i18n } from '@kbn/i18n'; -export const SOURCERER = i18n.translate('xpack.securitySolution.indexPatterns.dataSourcesLabel', { - defaultMessage: 'Data sources', +export const CALL_OUT_TITLE = i18n.translate('xpack.securitySolution.indexPatterns.callOutTitle', { + defaultMessage: 'Data view cannot be modified on this page', }); -export const SIEM_DATA_VIEW_LABEL = i18n.translate( - 'xpack.securitySolution.indexPatterns.kipLabel', +export const CALL_OUT_TIMELINE_TITLE = i18n.translate( + 'xpack.securitySolution.indexPatterns.callOutTimelineTitle', { - defaultMessage: 'Default Security Data View', + defaultMessage: 'Data view cannot be modified when show only detection alerts is selected', } ); -export const SELECT_INDEX_PATTERNS = i18n.translate('xpack.securitySolution.indexPatterns.help', { - defaultMessage: 'Data sources selection', +export const DATA_VIEW = i18n.translate('xpack.securitySolution.indexPatterns.dataViewLabel', { + defaultMessage: 'Data view', }); +export const MODIFIED_BADGE_TITLE = i18n.translate( + 'xpack.securitySolution.indexPatterns.modifiedBadgeTitle', + { + defaultMessage: 'Modified', + } +); + +export const ALERTS_BADGE_TITLE = i18n.translate( + 'xpack.securitySolution.indexPatterns.alertsBadgeTitle', + { + defaultMessage: 'Alerts', + } +); + +export const SECURITY_DEFAULT_DATA_VIEW_LABEL = i18n.translate( + 'xpack.securitySolution.indexPatterns.securityDefaultDataViewLabel', + { + defaultMessage: 'Security Default Data View', + } +); + +export const SIEM_SECURITY_DATA_VIEW_LABEL = i18n.translate( + 'xpack.securitySolution.indexPatterns.securityDataViewLabel', + { + defaultMessage: 'Security Data View', + } +); + +export const SELECT_DATA_VIEW = i18n.translate( + 'xpack.securitySolution.indexPatterns.selectDataView', + { + defaultMessage: 'Data view selection', + } +); export const SAVE_INDEX_PATTERNS = i18n.translate('xpack.securitySolution.indexPatterns.save', { defaultMessage: 'Save', }); -export const INDEX_PATTERNS_SELECTION_LABEL = i18n.translate( - 'xpack.securitySolution.indexPatterns.selectionLabel', +export const INDEX_PATTERNS_CHOOSE_DATA_VIEW_LABEL = i18n.translate( + 'xpack.securitySolution.indexPatterns.chooseDataViewLabel', + { + defaultMessage: 'Choose data view', + } +); + +export const INDEX_PATTERNS_ADVANCED_OPTIONS_TITLE = i18n.translate( + 'xpack.securitySolution.indexPatterns.advancedOptionsTitle', + { + defaultMessage: 'Advanced options', + } +); + +export const INDEX_PATTERNS_LABEL = i18n.translate( + 'xpack.securitySolution.indexPatterns.indexPatternsLabel', { - defaultMessage: 'Choose the source of the data on this page', + defaultMessage: 'Index patterns', + } +); + +export const INDEX_PATTERNS_DESCRIPTIONS = i18n.translate( + 'xpack.securitySolution.indexPatterns.descriptionsLabel', + { + defaultMessage: + 'These are the index patterns currently selected. Filtering out index patterns from your data view can help improve overall performance.', } ); @@ -54,3 +110,10 @@ export const PICK_INDEX_PATTERNS = i18n.translate( defaultMessage: 'Pick index patterns', } ); + +export const ALERTS_CHECKBOX_LABEL = i18n.translate( + 'xpack.securitySolution.indexPatterns.onlyDetectionAlertsLabel', + { + defaultMessage: 'Show only detection alerts', + } +); diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/use_pick_index_patterns.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/use_pick_index_patterns.tsx new file mode 100644 index 0000000000000..2ed2319499398 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/use_pick_index_patterns.tsx @@ -0,0 +1,167 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { EuiComboBoxOptionOption } from '@elastic/eui'; +import { getScopePatternListSelection } from '../../store/sourcerer/helpers'; +import { sourcererModel } from '../../store/sourcerer'; +import { getPatternListWithoutSignals } from './helpers'; +import { SourcererScopeName } from '../../store/sourcerer/model'; + +interface UsePickIndexPatternsProps { + dataViewId: string; + defaultDataViewId: string; + isOnlyDetectionAlerts: boolean; + kibanaDataViews: sourcererModel.SourcererModel['kibanaDataViews']; + scopeId: sourcererModel.SourcererScopeName; + selectedPatterns: string[]; + signalIndexName: string | null; +} + +export type ModifiedTypes = 'modified' | 'alerts' | ''; + +interface UsePickIndexPatterns { + isModified: ModifiedTypes; + onChangeCombo: (newSelectedDataViewId: Array>) => void; + renderOption: ({ value }: EuiComboBoxOptionOption) => React.ReactElement; + selectableOptions: Array>; + selectedOptions: Array>; + setIndexPatternsByDataView: (newSelectedDataViewId: string, isAlerts?: boolean) => void; +} + +const patternListToOptions = (patternList: string[], selectablePatterns?: string[]) => + patternList.sort().map((s) => ({ + label: s, + value: s, + ...(selectablePatterns != null ? { disabled: !selectablePatterns.includes(s) } : {}), + })); + +export const usePickIndexPatterns = ({ + dataViewId, + defaultDataViewId, + isOnlyDetectionAlerts, + kibanaDataViews, + scopeId, + selectedPatterns, + signalIndexName, +}: UsePickIndexPatternsProps): UsePickIndexPatterns => { + const alertsOptions = useMemo( + () => (signalIndexName ? patternListToOptions([signalIndexName]) : []), + [signalIndexName] + ); + + const { patternList, selectablePatterns } = useMemo(() => { + if (isOnlyDetectionAlerts && signalIndexName) { + return { + patternList: [signalIndexName], + selectablePatterns: [signalIndexName], + }; + } + const theDataView = kibanaDataViews.find((dataView) => dataView.id === dataViewId); + return theDataView != null + ? scopeId === sourcererModel.SourcererScopeName.default + ? { + patternList: getPatternListWithoutSignals( + theDataView.title + .split(',') + // remove duplicates patterns from selector + .filter((pattern, i, self) => self.indexOf(pattern) === i), + signalIndexName + ), + selectablePatterns: getPatternListWithoutSignals( + theDataView.patternList, + signalIndexName + ), + } + : { + patternList: theDataView.title + .split(',') + // remove duplicates patterns from selector + .filter((pattern, i, self) => self.indexOf(pattern) === i), + selectablePatterns: theDataView.patternList, + } + : { patternList: [], selectablePatterns: [] }; + }, [dataViewId, isOnlyDetectionAlerts, kibanaDataViews, scopeId, signalIndexName]); + + const selectableOptions = useMemo( + () => patternListToOptions(patternList, selectablePatterns), + [patternList, selectablePatterns] + ); + const [selectedOptions, setSelectedOptions] = useState>>( + isOnlyDetectionAlerts ? alertsOptions : patternListToOptions(selectedPatterns) + ); + + const getDefaultSelectedOptionsByDataView = useCallback( + (id: string, isAlerts: boolean = false): Array> => + scopeId === SourcererScopeName.detections || isAlerts + ? alertsOptions + : patternListToOptions( + getScopePatternListSelection( + kibanaDataViews.find((dataView) => dataView.id === id), + scopeId, + signalIndexName, + id === defaultDataViewId + ) + ), + [alertsOptions, kibanaDataViews, scopeId, signalIndexName, defaultDataViewId] + ); + + const defaultSelectedPatternsAsOptions = useMemo( + () => getDefaultSelectedOptionsByDataView(dataViewId), + [dataViewId, getDefaultSelectedOptionsByDataView] + ); + + const [isModified, setIsModified] = useState<'modified' | 'alerts' | ''>(''); + const onSetIsModified = useCallback( + (patterns?: string[]) => { + if (isOnlyDetectionAlerts) { + return setIsModified('alerts'); + } + const modifiedPatterns = patterns != null ? patterns : selectedPatterns; + const isPatternsModified = + defaultSelectedPatternsAsOptions.length !== modifiedPatterns.length || + !defaultSelectedPatternsAsOptions.every((option) => + modifiedPatterns.find((pattern) => option.value === pattern) + ); + return setIsModified(isPatternsModified ? 'modified' : ''); + }, + [defaultSelectedPatternsAsOptions, isOnlyDetectionAlerts, selectedPatterns] + ); + + // when scope updates, check modified to set/remove alerts label + useEffect(() => { + setSelectedOptions( + scopeId === SourcererScopeName.detections + ? alertsOptions + : patternListToOptions(selectedPatterns) + ); + onSetIsModified(selectedPatterns); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [scopeId, selectedPatterns]); + + const onChangeCombo = useCallback((newSelectedOptions) => { + setSelectedOptions(newSelectedOptions); + }, []); + + const renderOption = useCallback( + ({ value }) => {value}, + [] + ); + + const setIndexPatternsByDataView = (newSelectedDataViewId: string, isAlerts?: boolean) => { + setSelectedOptions(getDefaultSelectedOptionsByDataView(newSelectedDataViewId, isAlerts)); + }; + + return { + isModified, + onChangeCombo, + renderOption, + selectableOptions, + selectedOptions, + setIndexPatternsByDataView, + }; +}; diff --git a/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx b/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx index 4ca8bf037261a..2edfc1336269f 100644 --- a/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx @@ -13,7 +13,15 @@ import { sourcererActions, sourcererSelectors } from '../../store/sourcerer'; import { SelectedDataView, SourcererScopeName } from '../../store/sourcerer/model'; import { useUserInfo } from '../../../detections/components/user_info'; import { timelineSelectors } from '../../../timelines/store/timeline'; -import { ALERTS_PATH, CASES_PATH, RULES_PATH, UEBA_PATH } from '../../../../common/constants'; +import { + ALERTS_PATH, + CASES_PATH, + HOSTS_PATH, + NETWORK_PATH, + OVERVIEW_PATH, + RULES_PATH, + UEBA_PATH, +} from '../../../../common/constants'; import { TimelineId } from '../../../../common'; import { useDeepEqualSelector } from '../../hooks/use_selector'; import { getScopePatternListSelection } from '../../store/sourcerer/helpers'; @@ -300,3 +308,24 @@ export const getScopeFromPath = ( }) == null ? SourcererScopeName.default : SourcererScopeName.detections; + +export const sourcererPaths = [ + ALERTS_PATH, + `${RULES_PATH}/id/:id`, + HOSTS_PATH, + NETWORK_PATH, + OVERVIEW_PATH, + UEBA_PATH, +]; + +export const showSourcererByPath = (pathname: string): boolean => + matchPath(pathname, { + path: sourcererPaths, + strict: false, + }) != null; + +export const isAlertsOrRulesDetailsPage = (pathname: string): boolean => + matchPath(pathname, { + path: [ALERTS_PATH, `${RULES_PATH}/id/:id`], + strict: false, + }) != null; diff --git a/x-pack/plugins/security_solution/public/common/store/sourcerer/helpers.ts b/x-pack/plugins/security_solution/public/common/store/sourcerer/helpers.ts index 1b4efa72127f3..c99ed720c7f00 100644 --- a/x-pack/plugins/security_solution/public/common/store/sourcerer/helpers.ts +++ b/x-pack/plugins/security_solution/public/common/store/sourcerer/helpers.ts @@ -37,15 +37,7 @@ export const getScopePatternListSelection = ( // set to signalIndexName whether or not it exists yet in the patternList return (signalIndexName != null ? [signalIndexName] : []).sort(); case SourcererScopeName.timeline: - return ( - signalIndexName != null - ? [ - // remove signalIndexName in case its already in there and add it whether or not it exists yet in the patternList - ...patternList.filter((index) => index !== signalIndexName), - signalIndexName, - ] - : patternList - ).sort(); + return patternList.sort(); } }; @@ -96,16 +88,14 @@ export const validateSelectedPatterns = ( selectedDataViewId: dataView?.id ?? null, selectedPatterns, ...(isEmpty(selectedPatterns) - ? id === SourcererScopeName.timeline - ? defaultDataViewByEventType({ state, eventType }) - : { - selectedPatterns: getScopePatternListSelection( - dataView ?? state.defaultDataView, - id, - state.signalIndexName, - (dataView ?? state.defaultDataView).id === state.defaultDataView.id - ), - } + ? { + selectedPatterns: getScopePatternListSelection( + dataView ?? state.defaultDataView, + id, + state.signalIndexName, + (dataView ?? state.defaultDataView).id === state.defaultDataView.id + ), + } : {}), loading: false, }, diff --git a/x-pack/plugins/security_solution/public/detections/components/detection_engine_header_page/index.tsx b/x-pack/plugins/security_solution/public/detections/components/detection_engine_header_page/index.tsx index 92911ab285375..44f27b690fbc7 100644 --- a/x-pack/plugins/security_solution/public/detections/components/detection_engine_header_page/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/detection_engine_header_page/index.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { HeaderPage, HeaderPageProps } from '../../../common/components/header_page'; const DetectionEngineHeaderPageComponent: React.FC = (props) => ( - + ); export const DetectionEngineHeaderPage = React.memo(DetectionEngineHeaderPageComponent); diff --git a/x-pack/plugins/security_solution/public/overview/pages/overview.tsx b/x-pack/plugins/security_solution/public/overview/pages/overview.tsx index 3a98f062db65d..67ee6c55ac06f 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/overview.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/overview.tsx @@ -28,8 +28,6 @@ import { EndpointNotice } from '../components/endpoint_notice'; import { useMessagesStorage } from '../../common/containers/local_storage/use_messages_storage'; import { ENDPOINT_METADATA_INDEX } from '../../../common/constants'; import { useSourcererDataView } from '../../common/containers/sourcerer'; -import { Sourcerer } from '../../common/components/sourcerer'; -import { SourcererScopeName } from '../../common/store/sourcerer/model'; import { useDeepEqualSelector } from '../../common/hooks/use_selector'; import { ThreatIntelLinkPanel } from '../components/overview_cti_links'; import { useIsThreatIntelModuleEnabled } from '../containers/overview_cti_links/use_is_threat_intel_module_enabled'; @@ -96,7 +94,6 @@ const OverviewComponent = () => { )} - diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx index 6cb0e6f2e7982..4bd963b21a7f1 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx @@ -42,7 +42,6 @@ import { requiredFieldsForActions } from '../../../../detections/components/aler import { ExitFullScreen } from '../../../../common/components/exit_full_screen'; import { SuperDatePicker } from '../../../../common/components/super_date_picker'; import { EventDetailsWidthProvider } from '../../../../common/components/events_viewer/event_details_width_context'; -import { PickEventType } from '../search_or_filter/pick_events'; import { inputsModel, inputsSelectors, State } from '../../../../common/store'; import { sourcererActions } from '../../../../common/store/sourcerer'; import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; @@ -57,6 +56,7 @@ import { DetailsPanel } from '../../side_panel'; import { EqlQueryBarTimeline } from '../query_bar/eql'; import { defaultControlColumn } from '../body/control_columns'; import { Sort } from '../body/sort'; +import { Sourcerer } from '../../../../common/components/sourcerer'; const TimelineHeaderContainer = styled.div` margin-top: 6px; @@ -283,10 +283,7 @@ export const EqlTabContentComponent: React.FC = ({ - + diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx index 5f6f2796d4ba9..6d53e7194306c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx @@ -46,7 +46,6 @@ import { import { requiredFieldsForActions } from '../../../../detections/components/alerts_table/default_config'; import { SuperDatePicker } from '../../../../common/components/super_date_picker'; import { EventDetailsWidthProvider } from '../../../../common/components/events_viewer/event_details_width_context'; -import { PickEventType } from '../search_or_filter/pick_events'; import { inputsModel, inputsSelectors, State } from '../../../../common/store'; import { sourcererActions } from '../../../../common/store/sourcerer'; import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; @@ -61,6 +60,7 @@ import { DetailsPanel } from '../../side_panel'; import { ExitFullScreen } from '../../../../common/components/exit_full_screen'; import { defaultControlColumn } from '../body/control_columns'; import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; +import { Sourcerer } from '../../../../common/components/sourcerer'; const TimelineHeaderContainer = styled.div` margin-top: 6px; @@ -358,10 +358,7 @@ export const QueryTabContentComponent: React.FC = ({ - + diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/pick_events.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/pick_events.test.tsx deleted file mode 100644 index 47ea0f781f7c3..0000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/pick_events.test.tsx +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { fireEvent, render, within } from '@testing-library/react'; -import { EuiToolTip } from '@elastic/eui'; - -import React from 'react'; -import { PickEventType } from './pick_events'; -import { - createSecuritySolutionStorageMock, - kibanaObservable, - mockGlobalState, - mockSourcererState, - SUB_PLUGINS_REDUCER, - TestProviders, -} from '../../../../common/mock'; -import { TimelineEventsType } from '../../../../../common'; -import { createStore } from '../../../../common/store'; -import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; - -jest.mock('@elastic/eui', () => { - const actual = jest.requireActual('@elastic/eui'); - return { - ...actual, - EuiToolTip: jest.fn(), - }; -}); - -describe('Pick Events/Timeline Sourcerer', () => { - const defaultProps = { - eventType: 'all' as TimelineEventsType, - onChangeEventTypeAndIndexesName: jest.fn(), - }; - const initialPatterns = [ - ...mockSourcererState.defaultDataView.patternList.filter( - (p) => p !== mockSourcererState.signalIndexName - ), - mockSourcererState.signalIndexName, - ]; - const { storage } = createSecuritySolutionStorageMock(); - - // const state = { - // ...mockGlobalState, - // sourcerer: { - // ...mockGlobalState.sourcerer, - // kibanaIndexPatterns: [ - // { id: '1234', title: 'auditbeat-*' }, - // { id: '9100', title: 'filebeat-*' }, - // { id: '9100', title: 'auditbeat-*,filebeat-*' }, - // { id: '5678', title: 'auditbeat-*,.siem-signals-default' }, - // ], - // configIndexPatterns: - // mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.timeline].selectedPatterns, - // signalIndexName: mockGlobalState.sourcerer.signalIndexName, - // sourcererScopes: { - // ...mockGlobalState.sourcerer.sourcererScopes, - // [SourcererScopeName.timeline]: { - // ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.timeline], - // loading: false, - // selectedPatterns: ['filebeat-*'], - // }, - // }, - // }, - // }; - // const store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - const state = { - ...mockGlobalState, - sourcerer: { - ...mockGlobalState.sourcerer, - sourcererScopes: { - ...mockGlobalState.sourcerer.sourcererScopes, - [SourcererScopeName.timeline]: { - ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.timeline], - loading: false, - selectedDataViewId: mockGlobalState.sourcerer.defaultDataView.id, - selectedPatterns: ['filebeat-*'], - }, - }, - }, - }; - const store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - const mockTooltip = ({ - tooltipContent, - children, - }: { - tooltipContent: string; - children: React.ReactElement; - }) => ( -
    - {tooltipContent} - {children} -
    - ); - - beforeAll(() => { - (EuiToolTip as unknown as jest.Mock).mockImplementation(mockTooltip); - }); - beforeEach(() => { - jest.clearAllMocks(); - jest.restoreAllMocks(); - }); - it('renders', () => { - const wrapper = render( - - - - ); - fireEvent.click(wrapper.getByTestId('sourcerer-timeline-trigger')); - expect(wrapper.getByTestId('timeline-sourcerer').textContent).toEqual( - initialPatterns.sort().join('') - ); - fireEvent.click(wrapper.getByTestId(`sourcerer-accordion`)); - fireEvent.click(wrapper.getByTestId('comboBoxToggleListButton')); - const optionNodes = wrapper.getAllByTestId('sourcerer-option'); - expect(optionNodes.length).toBe(1); - }); - it('Removes duplicate options from options list', () => { - const store2 = createStore( - { - ...mockGlobalState, - sourcerer: { - ...mockGlobalState.sourcerer, - defaultDataView: { - ...mockGlobalState.sourcerer.defaultDataView, - id: '1234', - title: 'filebeat-*,auditbeat-*,auditbeat-*,auditbeat-*,auditbeat-*', - patternList: ['filebeat-*', 'auditbeat-*'], - }, - kibanaDataViews: [ - { - ...mockGlobalState.sourcerer.defaultDataView, - id: '1234', - title: 'filebeat-*,auditbeat-*,auditbeat-*,auditbeat-*,auditbeat-*', - patternList: ['filebeat-*', 'auditbeat-*'], - }, - ], - sourcererScopes: { - ...mockGlobalState.sourcerer.sourcererScopes, - [SourcererScopeName.timeline]: { - ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.timeline], - loading: false, - selectedDataViewId: '1234', - selectedPatterns: ['filebeat-*'], - }, - }, - }, - }, - SUB_PLUGINS_REDUCER, - kibanaObservable, - storage - ); - const wrapper = render( - - - - ); - fireEvent.click(wrapper.getByTestId(`sourcerer-timeline-trigger`)); - fireEvent.click(wrapper.getByTestId(`sourcerer-accordion`)); - fireEvent.click(wrapper.getByTestId(`comboBoxToggleListButton`)); - expect( - wrapper.getByTestId('comboBoxOptionsList timeline-sourcerer-optionsList').textContent - ).toEqual('auditbeat-*'); - }); - - it('renders tooltip', () => { - render( - - - - ); - - expect((EuiToolTip as unknown as jest.Mock).mock.calls[0][0].content).toEqual( - initialPatterns - .filter((p) => p != null) - .sort() - .join(', ') - ); - }); - - it('renders popover button inside tooltip', () => { - const wrapper = render( - - - - ); - const tooltip = wrapper.getByTestId('timeline-sourcerer-tooltip'); - expect(within(tooltip).getByTestId('sourcerer-timeline-trigger')).toBeTruthy(); - }); - - it('correctly filters options', () => { - const wrapper = render( - - - - ); - fireEvent.click(wrapper.getByTestId('sourcerer-timeline-trigger')); - fireEvent.click(wrapper.getByTestId('comboBoxToggleListButton')); - fireEvent.click(wrapper.getByTestId('sourcerer-accordion')); - const optionNodes = wrapper.getAllByTestId('sourcerer-option'); - expect(optionNodes.length).toBe(9); - }); - it('reset button works', () => { - const wrapper = render( - - - - ); - fireEvent.click(wrapper.getByTestId('sourcerer-timeline-trigger')); - expect(wrapper.getByTestId('timeline-sourcerer').textContent).toEqual('filebeat-*'); - - fireEvent.click(wrapper.getByTestId('sourcerer-reset')); - expect(wrapper.getByTestId('timeline-sourcerer').textContent).toEqual( - initialPatterns.sort().join('') - ); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/pick_events.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/pick_events.tsx deleted file mode 100644 index 791993d67135d..0000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/pick_events.tsx +++ /dev/null @@ -1,465 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiAccordion, - EuiButton, - EuiButtonEmpty, - EuiRadioGroup, - EuiComboBox, - EuiComboBoxOptionOption, - EuiHealth, - EuiIcon, - EuiFlexGroup, - EuiFlexItem, - EuiPopover, - EuiPopoverTitle, - EuiSpacer, - EuiText, - EuiToolTip, - EuiSuperSelect, -} from '@elastic/eui'; -import deepEqual from 'fast-deep-equal'; -import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; -import styled from 'styled-components'; - -import { sourcererSelectors } from '../../../../common/store'; -import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; -import { TimelineEventsType } from '../../../../../common'; -import * as i18n from './translations'; -import { getScopePatternListSelection } from '../../../../common/store/sourcerer/helpers'; -import { SIEM_DATA_VIEW_LABEL } from '../../../../common/components/sourcerer/translations'; -import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; - -const PopoverContent = styled.div` - width: 600px; -`; - -const ResetButton = styled(EuiButtonEmpty)` - width: fit-content; -`; - -const MyEuiButton = styled(EuiButton)` - .euiHealth { - vertical-align: middle; - } -`; - -const AllEuiHealth = styled(EuiHealth)` - margin-left: -2px; - svg { - stroke: #fff; - stroke-width: 1px; - stroke-linejoin: round; - width: 19px; - height: 19px; - margin-top: 1px; - z-index: 1; - } -`; - -const WarningEuiHealth = styled(EuiHealth)` - margin-left: -17px; - svg { - z-index: 0; - } -`; - -const AdvancedSettings = styled(EuiText)` - color: ${({ theme }) => theme.eui.euiColorPrimary}; -`; - -const ConfigHelper = styled(EuiText)` - margin-left: 4px; -`; - -const Filter = styled(EuiRadioGroup)` - margin-left: 4px; -`; - -const PickEventContainer = styled.div` - .euiSuperSelect { - width: 170px; - max-width: 170px; - button.euiSuperSelectControl { - padding-top: 3px; - } - } -`; - -const getEventTypeOptions = (isCustomDisabled: boolean = true, isDefaultPattern: boolean) => [ - { - id: 'all', - label: ( - - {i18n.ALL_EVENT} - - ), - }, - { - id: 'raw', - label: {i18n.RAW_EVENT}, - disabled: !isDefaultPattern, - }, - { - id: 'alert', - label: {i18n.DETECTION_ALERTS_EVENT}, - disabled: !isDefaultPattern, - }, - { - id: 'custom', - label: <>{i18n.CUSTOM_INDEX_PATTERNS}, - disabled: isCustomDisabled, - }, -]; - -interface PickEventTypeProps { - eventType: TimelineEventsType; - onChangeEventTypeAndIndexesName: ( - value: TimelineEventsType, - indexNames: string[], - dataViewId: string - ) => void; -} - -// AKA TimelineSourcerer -const PickEventTypeComponents: React.FC = ({ - eventType = 'all', - onChangeEventTypeAndIndexesName, -}) => { - const [isPopoverOpen, setPopover] = useState(false); - const [showAdvanceSettings, setAdvanceSettings] = useState(eventType === 'custom'); - const [filterEventType, setFilterEventType] = useState(eventType); - const sourcererScopeSelector = useMemo(() => sourcererSelectors.getSourcererScopeSelector(), []); - const { - defaultDataView, - kibanaDataViews, - signalIndexName, - sourcererScope: { loading, selectedPatterns, selectedDataViewId }, - }: sourcererSelectors.SourcererScopeSelector = useDeepEqualSelector((state) => - sourcererScopeSelector(state, SourcererScopeName.timeline) - ); - - const [dataViewId, setDataViewId] = useState(selectedDataViewId ?? ''); - const { patternList, selectablePatterns } = useMemo(() => { - const theDataView = kibanaDataViews.find((dataView) => dataView.id === dataViewId); - return theDataView != null - ? { - patternList: theDataView.title - .split(',') - // remove duplicates patterns from selector - .filter((pattern, i, self) => self.indexOf(pattern) === i), - selectablePatterns: theDataView.patternList, - } - : { patternList: [], selectablePatterns: [] }; - }, [kibanaDataViews, dataViewId]); - const [selectedOptions, setSelectedOptions] = useState>>( - selectedPatterns.map((indexName) => ({ - label: indexName, - value: indexName, - })) - ); - const isSavingDisabled = useMemo(() => selectedOptions.length === 0, [selectedOptions]); - const selectableOptions = useMemo( - () => - patternList.map((indexName) => ({ - label: indexName, - value: indexName, - 'data-test-subj': 'sourcerer-option', - disabled: !selectablePatterns.includes(indexName), - })), - [selectablePatterns, patternList] - ); - - const onChangeFilter = useCallback( - (filter) => { - setFilterEventType(filter); - if (filter === 'all' || filter === 'kibana') { - setSelectedOptions( - selectablePatterns.map((indexSelected) => ({ - label: indexSelected, - value: indexSelected, - })) - ); - } else if (filter === 'raw') { - setSelectedOptions( - (signalIndexName == null - ? selectablePatterns - : selectablePatterns.filter((index) => index !== signalIndexName) - ).map((indexSelected) => ({ - label: indexSelected, - value: indexSelected, - })) - ); - } else if (filter === 'alert') { - setSelectedOptions([ - { - label: signalIndexName ?? '', - value: signalIndexName ?? '', - }, - ]); - } - }, - [selectablePatterns, signalIndexName] - ); - - const onChangeCombo = useCallback( - (newSelectedOptions: Array>) => { - const localSelectedPatterns = newSelectedOptions - .map((nso) => nso.label) - .sort() - .join(); - if (localSelectedPatterns === selectablePatterns.sort().join()) { - setFilterEventType('all'); - } else if ( - dataViewId === defaultDataView.id && - localSelectedPatterns === - selectablePatterns - .filter((index) => index !== signalIndexName) - .sort() - .join() - ) { - setFilterEventType('raw'); - } else if (dataViewId === defaultDataView.id && localSelectedPatterns === signalIndexName) { - setFilterEventType('alert'); - } else { - setFilterEventType('custom'); - } - - setSelectedOptions(newSelectedOptions); - }, - [defaultDataView.id, dataViewId, selectablePatterns, signalIndexName] - ); - - const onChangeSuper = useCallback( - (newSelectedOption) => { - setFilterEventType('all'); - setDataViewId(newSelectedOption); - setSelectedOptions( - getScopePatternListSelection( - kibanaDataViews.find((dataView) => dataView.id === newSelectedOption), - SourcererScopeName.timeline, - signalIndexName, - newSelectedOption === defaultDataView.id - ).map((indexSelected: string) => ({ - label: indexSelected, - value: indexSelected, - })) - ); - }, - [defaultDataView.id, kibanaDataViews, signalIndexName] - ); - - const togglePopover = useCallback( - () => setPopover((prevIsPopoverOpen) => !prevIsPopoverOpen), - [] - ); - - const closePopover = useCallback(() => setPopover(false), []); - - const handleSaveIndices = useCallback(() => { - onChangeEventTypeAndIndexesName( - filterEventType, - selectedOptions.map((so) => so.label), - dataViewId - ); - setPopover(false); - }, [dataViewId, filterEventType, onChangeEventTypeAndIndexesName, selectedOptions]); - - const resetDataSources = useCallback(() => { - setDataViewId(defaultDataView.id); - setSelectedOptions( - getScopePatternListSelection( - defaultDataView, - SourcererScopeName.timeline, - signalIndexName, - true - ).map((indexSelected: string) => ({ - label: indexSelected, - value: indexSelected, - })) - ); - setFilterEventType(eventType); - }, [defaultDataView, eventType, signalIndexName]); - - const dataViewSelectOptions = useMemo( - () => - kibanaDataViews.map(({ title, id }) => ({ - inputDisplay: - id === defaultDataView.id ? ( - - {SIEM_DATA_VIEW_LABEL} - - ) : ( - - {title} - - ), - value: id, - })), - [defaultDataView.id, kibanaDataViews] - ); - - const filterOptions = useMemo( - () => getEventTypeOptions(filterEventType !== 'custom', dataViewId === defaultDataView.id), - [defaultDataView.id, filterEventType, dataViewId] - ); - - const button = useMemo(() => { - const options = getEventTypeOptions(true, dataViewId === defaultDataView.id); - return ( - - {options.find((opt) => opt.id === eventType)?.label} - - ); - }, [defaultDataView.id, eventType, dataViewId, loading, togglePopover]); - - const tooltipContent = useMemo( - () => (isPopoverOpen ? null : selectedPatterns.sort().join(', ')), - [isPopoverOpen, selectedPatterns] - ); - - const buttonWithTooptip = useMemo(() => { - return tooltipContent ? ( - - {button} - - ) : ( - button - ); - }, [button, tooltipContent]); - - const ButtonContent = useMemo( - () => ( - - {showAdvanceSettings - ? i18n.HIDE_INDEX_PATTERNS_ADVANCED_SETTINGS - : i18n.SHOW_INDEX_PATTERNS_ADVANCED_SETTINGS} - - ), - [showAdvanceSettings] - ); - - useEffect(() => { - const newSelectedOptions = selectedPatterns.map((indexSelected) => ({ - label: indexSelected, - value: indexSelected, - })); - setSelectedOptions((prevSelectedOptions) => { - if (!deepEqual(newSelectedOptions, prevSelectedOptions)) { - return newSelectedOptions; - } - return prevSelectedOptions; - }); - }, [selectedPatterns]); - - useEffect(() => { - setFilterEventType((prevFilter) => (prevFilter !== eventType ? eventType : prevFilter)); - setAdvanceSettings(eventType === 'custom'); - }, [eventType]); - - return ( - - - - - <>{i18n.SELECT_INDEX_PATTERNS} - - - - - - <> - - - - - - - {!showAdvanceSettings && ( - <> - - - {i18n.CONFIGURE_INDEX_PATTERNS} - - - )} - - - - - {i18n.DATA_SOURCES_RESET} - - - - - {i18n.SAVE_INDEX_PATTERNS} - - - - - - - ); -}; - -export const PickEventType = memo(PickEventTypeComponents); diff --git a/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.tsx b/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.tsx index 3a9b9b0d2693e..e59af74d9a478 100644 --- a/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.tsx +++ b/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.tsx @@ -46,7 +46,7 @@ export const TimelinesPageComponent: React.FC = () => { {indicesExist ? ( <> - + {capabilitiesCanUserCRUD && ( @@ -93,6 +93,7 @@ export const TimelinesPageComponent: React.FC = () => { ) : ( + )} diff --git a/x-pack/plugins/security_solution/public/ueba/pages/details/index.tsx b/x-pack/plugins/security_solution/public/ueba/pages/details/index.tsx index 72122aba3c4aa..51c06fffb7b63 100644 --- a/x-pack/plugins/security_solution/public/ueba/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/ueba/pages/details/index.tsx @@ -99,7 +99,6 @@ const UebaDetailsComponent: React.FC = ({ detailName, uebaDeta 高度な設定で構成できます。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b6b2744160423..9a83380158414 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -22426,13 +22426,10 @@ "xpack.securitySolution.hostsTable.unit": "{totalCount, plural, other {个主机}}", "xpack.securitySolution.hostsTable.versionTitle": "版本", "xpack.securitySolution.hoverActions.showTopTooltip": "显示排名靠前的{fieldName}", - "xpack.securitySolution.indexPatterns.dataSourcesLabel": "数据源", "xpack.securitySolution.indexPatterns.disabled": "在此页面上建议使用已禁用的索引模式,但是首先需要在 Kibana 索引模式设置中配置这些模式", - "xpack.securitySolution.indexPatterns.help": "数据源的选择", "xpack.securitySolution.indexPatterns.pickIndexPatternsCombo": "选取索引模式", "xpack.securitySolution.indexPatterns.resetButton": "重置", "xpack.securitySolution.indexPatterns.save": "保存", - "xpack.securitySolution.indexPatterns.selectionLabel": "在此页面上选择数据源", "xpack.securitySolution.insert.timeline.insertTimelineButton": "插入时间线链接", "xpack.securitySolution.inspect.modal.closeTitle": "关闭", "xpack.securitySolution.inspect.modal.indexPatternDescription": "连接到 Elasticsearch 索引的索引模式。可以在“Kibana”>“高级设置”中配置这些索引。", From 264bb7acdd20a63e5e10f4e27f02d1af03d109cd Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Thu, 11 Nov 2021 02:14:10 +0000 Subject: [PATCH 26/51] fix(NA): wrongly added include key on tsconfig.json for @kbn/monaco (#118210) * fix(NA): wrongly added include key on tsconfig.json for @kbn/monaco * fix(NA): @kbn/monaco structure to allow bazel build on windows --- packages/kbn-monaco/BUILD.bazel | 1 + packages/kbn-monaco/{ => src}/__jest__/jest.mocks.ts | 4 ++-- packages/kbn-monaco/{ => src}/__jest__/types.ts | 0 packages/kbn-monaco/src/painless/diagnostics_adapter.test.ts | 4 ++-- packages/kbn-monaco/tsconfig.json | 1 - 5 files changed, 5 insertions(+), 5 deletions(-) rename packages/kbn-monaco/{ => src}/__jest__/jest.mocks.ts (94%) rename packages/kbn-monaco/{ => src}/__jest__/types.ts (100%) diff --git a/packages/kbn-monaco/BUILD.bazel b/packages/kbn-monaco/BUILD.bazel index caf5f7c25b569..b2efa79f7fb34 100644 --- a/packages/kbn-monaco/BUILD.bazel +++ b/packages/kbn-monaco/BUILD.bazel @@ -11,6 +11,7 @@ SOURCE_FILES = glob( "src/**/*", ], exclude = [ + "**/__jest__", "**/*.test.*", "**/README.md", ], diff --git a/packages/kbn-monaco/__jest__/jest.mocks.ts b/packages/kbn-monaco/src/__jest__/jest.mocks.ts similarity index 94% rename from packages/kbn-monaco/__jest__/jest.mocks.ts rename to packages/kbn-monaco/src/__jest__/jest.mocks.ts index a210d7e171aa8..1df4f9b115002 100644 --- a/packages/kbn-monaco/__jest__/jest.mocks.ts +++ b/packages/kbn-monaco/src/__jest__/jest.mocks.ts @@ -33,8 +33,8 @@ const createMockModel = (ID: string) => { return model; }; -jest.mock('../src/monaco_imports', () => { - const original = jest.requireActual('../src/monaco_imports'); +jest.mock('../monaco_imports', () => { + const original = jest.requireActual('../monaco_imports'); const originalMonaco = original.monaco; const originalEditor = original.monaco.editor; diff --git a/packages/kbn-monaco/__jest__/types.ts b/packages/kbn-monaco/src/__jest__/types.ts similarity index 100% rename from packages/kbn-monaco/__jest__/types.ts rename to packages/kbn-monaco/src/__jest__/types.ts diff --git a/packages/kbn-monaco/src/painless/diagnostics_adapter.test.ts b/packages/kbn-monaco/src/painless/diagnostics_adapter.test.ts index 7c3a9b66a82e1..5d00ad726d031 100644 --- a/packages/kbn-monaco/src/painless/diagnostics_adapter.test.ts +++ b/packages/kbn-monaco/src/painless/diagnostics_adapter.test.ts @@ -5,11 +5,11 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import '../../__jest__/jest.mocks'; // Make sure this is the first import +import '../__jest__/jest.mocks'; // Make sure this is the first import import { Subscription } from 'rxjs'; -import { MockIModel } from '../../__jest__/types'; +import { MockIModel } from '../__jest__/types'; import { LangValidation } from '../types'; import { monaco } from '../monaco_imports'; import { ID } from './constants'; diff --git a/packages/kbn-monaco/tsconfig.json b/packages/kbn-monaco/tsconfig.json index 4a373843c555a..959051b17b782 100644 --- a/packages/kbn-monaco/tsconfig.json +++ b/packages/kbn-monaco/tsconfig.json @@ -14,6 +14,5 @@ }, "include": [ "src/**/*", - "__jest__/**/*", ] } From 40939b2c67e9434026a57adb6f4263653ae7f6bb Mon Sep 17 00:00:00 2001 From: Dominique Clarke Date: Wed, 10 Nov 2021 22:08:41 -0500 Subject: [PATCH 27/51] rename Analyze data labels to Explore data (#118096) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/components/app/RumDashboard/ActionMenu/index.tsx | 4 ++-- .../templates/apm_service_template/analyze_data_button.tsx | 4 ++-- .../public/components/shared/exploratory_view/index.tsx | 2 +- .../components/common/header/action_menu_content.test.tsx | 4 ++-- .../public/components/common/header/action_menu_content.tsx | 6 +++--- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ActionMenu/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ActionMenu/index.tsx index 3bf21de7487de..2a1badd0ae1d8 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ActionMenu/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ActionMenu/index.tsx @@ -19,14 +19,14 @@ import { InspectorHeaderLink } from '../../../shared/apm_header_action_menu/insp import { SERVICE_NAME } from '../../../../../common/elasticsearch_fieldnames'; const ANALYZE_DATA = i18n.translate('xpack.apm.analyzeDataButtonLabel', { - defaultMessage: 'Analyze data', + defaultMessage: 'Explore data', }); const ANALYZE_MESSAGE = i18n.translate( 'xpack.apm.analyzeDataButtonLabel.message', { defaultMessage: - 'EXPERIMENTAL - Analyze Data allows you to select and filter result data in any dimension and look for the cause or impact of performance problems.', + 'EXPERIMENTAL - Explore Data allows you to select and filter result data in any dimension and look for the cause or impact of performance problems.', } ); diff --git a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/analyze_data_button.tsx b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/analyze_data_button.tsx index a4fc964a444c9..5fa37050e71a6 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/analyze_data_button.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/analyze_data_button.tsx @@ -79,12 +79,12 @@ export function AnalyzeDataButton() { position="top" content={i18n.translate('xpack.apm.analyzeDataButton.tooltip', { defaultMessage: - 'EXPERIMENTAL - Analyze Data allows you to select and filter result data in any dimension, and look for the cause or impact of performance problems', + 'EXPERIMENTAL - Explore Data allows you to select and filter result data in any dimension, and look for the cause or impact of performance problems', })} > {i18n.translate('xpack.apm.analyzeDataButton.label', { - defaultMessage: 'Analyze data', + defaultMessage: 'Explore data', })} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/index.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/index.tsx index 3de29b02853e8..1fc38ab79de7f 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/index.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/index.tsx @@ -36,7 +36,7 @@ export function ExploratoryViewPage({ useBreadcrumbs([ { text: i18n.translate('xpack.observability.overview.exploratoryView', { - defaultMessage: 'Analyze data', + defaultMessage: 'Explore data', }), }, ]); diff --git a/x-pack/plugins/uptime/public/components/common/header/action_menu_content.test.tsx b/x-pack/plugins/uptime/public/components/common/header/action_menu_content.test.tsx index 76b9378ca4ff6..47dc2084a788f 100644 --- a/x-pack/plugins/uptime/public/components/common/header/action_menu_content.test.tsx +++ b/x-pack/plugins/uptime/public/components/common/header/action_menu_content.test.tsx @@ -35,11 +35,11 @@ describe('ActionMenuContent', () => { const { getByLabelText, getByText } = render(); const analyzeAnchor = getByLabelText( - 'Navigate to the "Analyze Data" view to visualize Synthetics/User data' + 'Navigate to the "Explore Data" view to visualize Synthetics/User data' ); expect(analyzeAnchor.getAttribute('href')).toContain('/app/observability/exploratory-view'); - expect(getByText('Analyze data')); + expect(getByText('Explore data')); }); it('renders Add Data link', () => { diff --git a/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx b/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx index 26f9e28101ea4..7b510432f773b 100644 --- a/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx +++ b/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx @@ -26,12 +26,12 @@ const ADD_DATA_LABEL = i18n.translate('xpack.uptime.addDataButtonLabel', { }); const ANALYZE_DATA = i18n.translate('xpack.uptime.analyzeDataButtonLabel', { - defaultMessage: 'Analyze data', + defaultMessage: 'Explore data', }); const ANALYZE_MESSAGE = i18n.translate('xpack.uptime.analyzeDataButtonLabel.message', { defaultMessage: - 'EXPERIMENTAL - Analyze Data allows you to select and filter result data in any dimension and look for the cause or impact of performance problems.', + 'EXPERIMENTAL - Explore Data allows you to select and filter result data in any dimension and look for the cause or impact of performance problems.', }); export function ActionMenuContent(): React.ReactElement { @@ -87,7 +87,7 @@ export function ActionMenuContent(): React.ReactElement { {ANALYZE_MESSAGE}

    }> Date: Wed, 10 Nov 2021 20:43:54 -0700 Subject: [PATCH 28/51] skip flaky suite (#118272) --- .../feature_controls/saved_objects_management_security.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts b/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts index 8b6474b0679b7..c0b81ed8443e5 100644 --- a/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts +++ b/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts @@ -16,7 +16,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { let version: string = ''; const find = getService('find'); - describe('feature controls saved objects management', () => { + // FLAKY: https://github.com/elastic/kibana/issues/118272 + describe.skip('feature controls saved objects management', () => { before(async () => { version = await kibanaServer.version.get(); await kibanaServer.importExport.load( From f4b61d01be7ecccbdc24c77668e41ab198c24379 Mon Sep 17 00:00:00 2001 From: Joe Portner <5295965+jportner@users.noreply.github.com> Date: Wed, 10 Nov 2021 22:59:38 -0500 Subject: [PATCH 29/51] Improve es-archiver saving/loading (#118255) --- packages/kbn-es-archiver/src/actions/load.ts | 4 +- packages/kbn-es-archiver/src/actions/save.ts | 6 +- packages/kbn-es-archiver/src/cli.ts | 24 +- packages/kbn-es-archiver/src/es_archiver.ts | 13 +- .../docs/generate_doc_records_stream.test.ts | 231 +++++++++++++----- .../lib/docs/generate_doc_records_stream.ts | 7 +- .../indices/create_index_stream.test.mock.ts | 15 ++ .../lib/indices/create_index_stream.test.ts | 73 ++++++ .../src/lib/indices/create_index_stream.ts | 17 +- .../generate_index_records_stream.test.ts | 55 ++++- .../indices/generate_index_records_stream.ts | 14 +- .../src/lib/indices/kibana_index.ts | 11 +- 12 files changed, 377 insertions(+), 93 deletions(-) create mode 100644 packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.mock.ts diff --git a/packages/kbn-es-archiver/src/actions/load.ts b/packages/kbn-es-archiver/src/actions/load.ts index 619c946f0c988..0a7235c566b52 100644 --- a/packages/kbn-es-archiver/src/actions/load.ts +++ b/packages/kbn-es-archiver/src/actions/load.ts @@ -40,6 +40,7 @@ export async function loadAction({ inputDir, skipExisting, useCreate, + docsOnly, client, log, kbnClient, @@ -47,6 +48,7 @@ export async function loadAction({ inputDir: string; skipExisting: boolean; useCreate: boolean; + docsOnly?: boolean; client: Client; log: ToolingLog; kbnClient: KbnClient; @@ -76,7 +78,7 @@ export async function loadAction({ await createPromiseFromStreams([ recordStream, - createCreateIndexStream({ client, stats, skipExisting, log }), + createCreateIndexStream({ client, stats, skipExisting, docsOnly, log }), createIndexDocRecordsStream(client, stats, progress, useCreate), ]); diff --git a/packages/kbn-es-archiver/src/actions/save.ts b/packages/kbn-es-archiver/src/actions/save.ts index 07ed2b206c1dd..9cb5be05ac060 100644 --- a/packages/kbn-es-archiver/src/actions/save.ts +++ b/packages/kbn-es-archiver/src/actions/save.ts @@ -27,6 +27,7 @@ export async function saveAction({ client, log, raw, + keepIndexNames, query, }: { outputDir: string; @@ -34,6 +35,7 @@ export async function saveAction({ client: Client; log: ToolingLog; raw: boolean; + keepIndexNames?: boolean; query?: Record; }) { const name = relative(REPO_ROOT, outputDir); @@ -50,7 +52,7 @@ export async function saveAction({ // export and save the matching indices to mappings.json createPromiseFromStreams([ createListStream(indices), - createGenerateIndexRecordsStream(client, stats), + createGenerateIndexRecordsStream({ client, stats, keepIndexNames }), ...createFormatArchiveStreams(), createWriteStream(resolve(outputDir, 'mappings.json')), ] as [Readable, ...Writable[]]), @@ -58,7 +60,7 @@ export async function saveAction({ // export all documents from matching indexes into data.json.gz createPromiseFromStreams([ createListStream(indices), - createGenerateDocRecordsStream({ client, stats, progress, query }), + createGenerateDocRecordsStream({ client, stats, progress, keepIndexNames, query }), ...createFormatArchiveStreams({ gzip: !raw }), createWriteStream(resolve(outputDir, `data.json${raw ? '' : '.gz'}`)), ] as [Readable, ...Writable[]]), diff --git a/packages/kbn-es-archiver/src/cli.ts b/packages/kbn-es-archiver/src/cli.ts index db54a3bade74b..e54b4d5fbdb52 100644 --- a/packages/kbn-es-archiver/src/cli.ts +++ b/packages/kbn-es-archiver/src/cli.ts @@ -143,11 +143,12 @@ export function runCli() { $ node scripts/es_archiver save test/functional/es_archives/my_test_data logstash-* `, flags: { - boolean: ['raw'], + boolean: ['raw', 'keep-index-names'], string: ['query'], help: ` - --raw don't gzip the archives - --query query object to limit the documents being archived, needs to be properly escaped JSON + --raw don't gzip the archives + --keep-index-names don't change the names of Kibana indices to .kibana_1 + --query query object to limit the documents being archived, needs to be properly escaped JSON `, }, async run({ flags, esArchiver, statsMeta }) { @@ -168,6 +169,11 @@ export function runCli() { throw createFlagError('--raw does not take a value'); } + const keepIndexNames = flags['keep-index-names']; + if (typeof keepIndexNames !== 'boolean') { + throw createFlagError('--keep-index-names does not take a value'); + } + const query = flags.query; let parsedQuery; if (typeof query === 'string' && query.length > 0) { @@ -178,7 +184,7 @@ export function runCli() { } } - await esArchiver.save(path, indices, { raw, query: parsedQuery }); + await esArchiver.save(path, indices, { raw, keepIndexNames, query: parsedQuery }); }, }) .command({ @@ -196,9 +202,10 @@ export function runCli() { $ node scripts/es_archiver load my_test_data --config ../config.js `, flags: { - boolean: ['use-create'], + boolean: ['use-create', 'docs-only'], help: ` --use-create use create instead of index for loading documents + --docs-only load only documents, not indices `, }, async run({ flags, esArchiver, statsMeta }) { @@ -217,7 +224,12 @@ export function runCli() { throw createFlagError('--use-create does not take a value'); } - await esArchiver.load(path, { useCreate }); + const docsOnly = flags['docs-only']; + if (typeof docsOnly !== 'boolean') { + throw createFlagError('--docs-only does not take a value'); + } + + await esArchiver.load(path, { useCreate, docsOnly }); }, }) .command({ diff --git a/packages/kbn-es-archiver/src/es_archiver.ts b/packages/kbn-es-archiver/src/es_archiver.ts index ed27bc0afcf34..354197a98fa46 100644 --- a/packages/kbn-es-archiver/src/es_archiver.ts +++ b/packages/kbn-es-archiver/src/es_archiver.ts @@ -50,16 +50,22 @@ export class EsArchiver { * @param {String|Array} indices - the indices to archive * @param {Object} options * @property {Boolean} options.raw - should the archive be raw (unzipped) or not + * @property {Boolean} options.keepIndexNames - should the Kibana index name be kept as-is or renamed */ async save( path: string, indices: string | string[], - { raw = false, query }: { raw?: boolean; query?: Record } = {} + { + raw = false, + keepIndexNames = false, + query, + }: { raw?: boolean; keepIndexNames?: boolean; query?: Record } = {} ) { return await saveAction({ outputDir: Path.resolve(this.baseDir, path), indices, raw, + keepIndexNames, client: this.client, log: this.log, query, @@ -74,18 +80,21 @@ export class EsArchiver { * @property {Boolean} options.skipExisting - should existing indices * be ignored or overwritten * @property {Boolean} options.useCreate - use a create operation instead of index for documents + * @property {Boolean} options.docsOnly - load only documents, not indices */ async load( path: string, { skipExisting = false, useCreate = false, - }: { skipExisting?: boolean; useCreate?: boolean } = {} + docsOnly = false, + }: { skipExisting?: boolean; useCreate?: boolean; docsOnly?: boolean } = {} ) { return await loadAction({ inputDir: this.findArchive(path), skipExisting: !!skipExisting, useCreate: !!useCreate, + docsOnly, client: this.client, log: this.log, kbnClient: this.kbnClient, diff --git a/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.test.ts b/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.test.ts index 2902812f51493..3b5f1f777b0e3 100644 --- a/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.test.ts +++ b/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.test.ts @@ -20,48 +20,24 @@ import { createStats } from '../stats'; const log = new ToolingLog(); -it('transforms each input index to a stream of docs using scrollSearch helper', async () => { - const responses: any = { - foo: [ - { - body: { - hits: { - total: 5, - hits: [ - { _index: 'foo', _type: '_doc', _id: '0', _source: {} }, - { _index: 'foo', _type: '_doc', _id: '1', _source: {} }, - { _index: 'foo', _type: '_doc', _id: '2', _source: {} }, - ], - }, - }, - }, - { - body: { - hits: { - total: 5, - hits: [ - { _index: 'foo', _type: '_doc', _id: '3', _source: {} }, - { _index: 'foo', _type: '_doc', _id: '4', _source: {} }, - ], - }, - }, - }, - ], - bar: [ - { - body: { - hits: { - total: 2, - hits: [ - { _index: 'bar', _type: '_doc', _id: '0', _source: {} }, - { _index: 'bar', _type: '_doc', _id: '1', _source: {} }, - ], - }, - }, - }, - ], - }; +interface SearchResponses { + [key: string]: Array<{ + body: { + hits: { + total: number; + hits: Array<{ + _index: string; + _type: string; + _id: string; + _source: Record; + }>; + }; + }; + }>; +} +function createMockClient(responses: SearchResponses) { + // TODO: replace with proper mocked client const client: any = { helpers: { scrollSearch: jest.fn(function* ({ index }) { @@ -71,29 +47,76 @@ it('transforms each input index to a stream of docs using scrollSearch helper', }), }, }; + return client; +} - const stats = createStats('test', log); - const progress = new Progress(); - - const results = await createPromiseFromStreams([ - createListStream(['bar', 'foo']), - createGenerateDocRecordsStream({ - client, - stats, - progress, - }), - createMapStream((record: any) => { - expect(record).toHaveProperty('type', 'doc'); - expect(record.value.source).toEqual({}); - expect(record.value.type).toBe('_doc'); - expect(record.value.index).toMatch(/^(foo|bar)$/); - expect(record.value.id).toMatch(/^\d+$/); - return `${record.value.index}:${record.value.id}`; - }), - createConcatStream([]), - ]); - - expect(client.helpers.scrollSearch).toMatchInlineSnapshot(` +describe('esArchiver: createGenerateDocRecordsStream()', () => { + it('transforms each input index to a stream of docs using scrollSearch helper', async () => { + const responses = { + foo: [ + { + body: { + hits: { + total: 5, + hits: [ + { _index: 'foo', _type: '_doc', _id: '0', _source: {} }, + { _index: 'foo', _type: '_doc', _id: '1', _source: {} }, + { _index: 'foo', _type: '_doc', _id: '2', _source: {} }, + ], + }, + }, + }, + { + body: { + hits: { + total: 5, + hits: [ + { _index: 'foo', _type: '_doc', _id: '3', _source: {} }, + { _index: 'foo', _type: '_doc', _id: '4', _source: {} }, + ], + }, + }, + }, + ], + bar: [ + { + body: { + hits: { + total: 2, + hits: [ + { _index: 'bar', _type: '_doc', _id: '0', _source: {} }, + { _index: 'bar', _type: '_doc', _id: '1', _source: {} }, + ], + }, + }, + }, + ], + }; + + const client = createMockClient(responses); + + const stats = createStats('test', log); + const progress = new Progress(); + + const results = await createPromiseFromStreams([ + createListStream(['bar', 'foo']), + createGenerateDocRecordsStream({ + client, + stats, + progress, + }), + createMapStream((record: any) => { + expect(record).toHaveProperty('type', 'doc'); + expect(record.value.source).toEqual({}); + expect(record.value.type).toBe('_doc'); + expect(record.value.index).toMatch(/^(foo|bar)$/); + expect(record.value.id).toMatch(/^\d+$/); + return `${record.value.index}:${record.value.id}`; + }), + createConcatStream([]), + ]); + + expect(client.helpers.scrollSearch).toMatchInlineSnapshot(` [MockFunction] { "calls": Array [ Array [ @@ -139,7 +162,7 @@ it('transforms each input index to a stream of docs using scrollSearch helper', ], } `); - expect(results).toMatchInlineSnapshot(` + expect(results).toMatchInlineSnapshot(` Array [ "bar:0", "bar:1", @@ -150,14 +173,14 @@ it('transforms each input index to a stream of docs using scrollSearch helper', "foo:4", ] `); - expect(progress).toMatchInlineSnapshot(` + expect(progress).toMatchInlineSnapshot(` Progress { "complete": 7, "loggingInterval": undefined, "total": 7, } `); - expect(stats).toMatchInlineSnapshot(` + expect(stats).toMatchInlineSnapshot(` Object { "bar": Object { "archived": false, @@ -193,4 +216,80 @@ it('transforms each input index to a stream of docs using scrollSearch helper', }, } `); + }); + + describe('keepIndexNames', () => { + it('changes .kibana* index names if keepIndexNames is not enabled', async () => { + const hits = [{ _index: '.kibana_7.16.0_001', _type: '_doc', _id: '0', _source: {} }]; + const responses = { + ['.kibana_7.16.0_001']: [{ body: { hits: { hits, total: hits.length } } }], + }; + const client = createMockClient(responses); + const stats = createStats('test', log); + const progress = new Progress(); + + const results = await createPromiseFromStreams([ + createListStream(['.kibana_7.16.0_001']), + createGenerateDocRecordsStream({ + client, + stats, + progress, + }), + createMapStream((record: { value: { index: string; id: string } }) => { + return `${record.value.index}:${record.value.id}`; + }), + createConcatStream([]), + ]); + expect(results).toEqual(['.kibana_1:0']); + }); + + it('does not change non-.kibana* index names if keepIndexNames is not enabled', async () => { + const hits = [{ _index: '.foo', _type: '_doc', _id: '0', _source: {} }]; + const responses = { + ['.foo']: [{ body: { hits: { hits, total: hits.length } } }], + }; + const client = createMockClient(responses); + const stats = createStats('test', log); + const progress = new Progress(); + + const results = await createPromiseFromStreams([ + createListStream(['.foo']), + createGenerateDocRecordsStream({ + client, + stats, + progress, + }), + createMapStream((record: { value: { index: string; id: string } }) => { + return `${record.value.index}:${record.value.id}`; + }), + createConcatStream([]), + ]); + expect(results).toEqual(['.foo:0']); + }); + + it('does not change .kibana* index names if keepIndexNames is enabled', async () => { + const hits = [{ _index: '.kibana_7.16.0_001', _type: '_doc', _id: '0', _source: {} }]; + const responses = { + ['.kibana_7.16.0_001']: [{ body: { hits: { hits, total: hits.length } } }], + }; + const client = createMockClient(responses); + const stats = createStats('test', log); + const progress = new Progress(); + + const results = await createPromiseFromStreams([ + createListStream(['.kibana_7.16.0_001']), + createGenerateDocRecordsStream({ + client, + stats, + progress, + keepIndexNames: true, + }), + createMapStream((record: { value: { index: string; id: string } }) => { + return `${record.value.index}:${record.value.id}`; + }), + createConcatStream([]), + ]); + expect(results).toEqual(['.kibana_7.16.0_001:0']); + }); + }); }); diff --git a/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.ts b/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.ts index a0636d6a3f76a..4bd44b649afd2 100644 --- a/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.ts +++ b/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.ts @@ -19,11 +19,13 @@ export function createGenerateDocRecordsStream({ client, stats, progress, + keepIndexNames, query, }: { client: Client; stats: Stats; progress: Progress; + keepIndexNames?: boolean; query?: Record; }) { return new Transform({ @@ -59,9 +61,10 @@ export function createGenerateDocRecordsStream({ this.push({ type: 'doc', value: { - // always rewrite the .kibana_* index to .kibana_1 so that + // if keepIndexNames is false, rewrite the .kibana_* index to .kibana_1 so that // when it is loaded it can skip migration, if possible - index: hit._index.startsWith('.kibana') ? '.kibana_1' : hit._index, + index: + hit._index.startsWith('.kibana') && !keepIndexNames ? '.kibana_1' : hit._index, type: hit._type, id: hit._id, source: hit._source, diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.mock.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.mock.ts new file mode 100644 index 0000000000000..d17bd33fa07ab --- /dev/null +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.mock.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { deleteKibanaIndices } from './kibana_index'; + +export const mockDeleteKibanaIndices = jest.fn() as jest.MockedFunction; + +jest.mock('./kibana_index', () => ({ + deleteKibanaIndices: mockDeleteKibanaIndices, +})); diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts index 3a8180b724e07..615555b405e44 100644 --- a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts @@ -6,6 +6,8 @@ * Side Public License, v 1. */ +import { mockDeleteKibanaIndices } from './create_index_stream.test.mock'; + import sinon from 'sinon'; import Chance from 'chance'; import { createPromiseFromStreams, createConcatStream, createListStream } from '@kbn/utils'; @@ -24,6 +26,10 @@ const chance = new Chance(); const log = createStubLogger(); +beforeEach(() => { + mockDeleteKibanaIndices.mockClear(); +}); + describe('esArchiver: createCreateIndexStream()', () => { describe('defaults', () => { it('deletes existing indices, creates all', async () => { @@ -167,6 +173,73 @@ describe('esArchiver: createCreateIndexStream()', () => { }); }); + describe('deleteKibanaIndices', () => { + function doTest(...indices: string[]) { + return createPromiseFromStreams([ + createListStream(indices.map((index) => createStubIndexRecord(index))), + createCreateIndexStream({ client: createStubClient(), stats: createStubStats(), log }), + createConcatStream([]), + ]); + } + + it('does not delete Kibana indices for indexes that do not start with .kibana', async () => { + await doTest('.foo'); + + expect(mockDeleteKibanaIndices).not.toHaveBeenCalled(); + }); + + it('deletes Kibana indices at most once for indices that start with .kibana', async () => { + // If we are loading the main Kibana index, we should delete all Kibana indices for backwards compatibility reasons. + await doTest('.kibana_7.16.0_001', '.kibana_task_manager_7.16.0_001'); + + expect(mockDeleteKibanaIndices).toHaveBeenCalledTimes(1); + expect(mockDeleteKibanaIndices).toHaveBeenCalledWith( + expect.not.objectContaining({ onlyTaskManager: true }) + ); + }); + + it('deletes Kibana task manager index at most once, using onlyTaskManager: true', async () => { + // If we are loading the Kibana task manager index, we should only delete that index, not any other Kibana indices. + await doTest('.kibana_task_manager_7.16.0_001', '.kibana_task_manager_7.16.0_002'); + + expect(mockDeleteKibanaIndices).toHaveBeenCalledTimes(1); + expect(mockDeleteKibanaIndices).toHaveBeenCalledWith( + expect.objectContaining({ onlyTaskManager: true }) + ); + }); + + it('deletes Kibana task manager index AND deletes all Kibana indices', async () => { + // Because we are reading from a stream, we can't look ahead to see if we'll eventually wind up deleting all Kibana indices. + // So, we first delete only the Kibana task manager indices, then we wind up deleting all Kibana indices. + await doTest('.kibana_task_manager_7.16.0_001', '.kibana_7.16.0_001'); + + expect(mockDeleteKibanaIndices).toHaveBeenCalledTimes(2); + expect(mockDeleteKibanaIndices).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ onlyTaskManager: true }) + ); + expect(mockDeleteKibanaIndices).toHaveBeenNthCalledWith( + 2, + expect.not.objectContaining({ onlyTaskManager: true }) + ); + }); + }); + + describe('docsOnly = true', () => { + it('passes through "hit" records without attempting to create indices', async () => { + const client = createStubClient(); + const stats = createStubStats(); + const output = await createPromiseFromStreams([ + createListStream([createStubIndexRecord('index'), createStubDocRecord('index', 1)]), + createCreateIndexStream({ client, stats, log, docsOnly: true }), + createConcatStream([]), + ]); + + sinon.assert.notCalled(client.indices.create as sinon.SinonSpy); + expect(output).toEqual([createStubDocRecord('index', 1)]); + }); + }); + describe('skipExisting = true', () => { it('ignores preexisting indexes', async () => { const client = createStubClient(['existing-index']); diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts index 50d13fc728c79..26472d72bef0f 100644 --- a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts @@ -29,11 +29,13 @@ export function createCreateIndexStream({ client, stats, skipExisting = false, + docsOnly = false, log, }: { client: Client; stats: Stats; skipExisting?: boolean; + docsOnly?: boolean; log: ToolingLog; }) { const skipDocsFromIndices = new Set(); @@ -42,6 +44,7 @@ export function createCreateIndexStream({ // previous indices are removed so we're starting w/ a clean slate for // migrations. This only needs to be done once per archive load operation. let kibanaIndexAlreadyDeleted = false; + let kibanaTaskManagerIndexAlreadyDeleted = false; async function handleDoc(stream: Readable, record: DocRecord) { if (skipDocsFromIndices.has(record.value.index)) { @@ -53,13 +56,21 @@ export function createCreateIndexStream({ async function handleIndex(record: DocRecord) { const { index, settings, mappings, aliases } = record.value; - const isKibana = index.startsWith('.kibana'); + const isKibanaTaskManager = index.startsWith('.kibana_task_manager'); + const isKibana = index.startsWith('.kibana') && !isKibanaTaskManager; + + if (docsOnly) { + return; + } async function attemptToCreate(attemptNumber = 1) { try { if (isKibana && !kibanaIndexAlreadyDeleted) { - await deleteKibanaIndices({ client, stats, log }); - kibanaIndexAlreadyDeleted = true; + await deleteKibanaIndices({ client, stats, log }); // delete all .kibana* indices + kibanaIndexAlreadyDeleted = kibanaTaskManagerIndexAlreadyDeleted = true; + } else if (isKibanaTaskManager && !kibanaTaskManagerIndexAlreadyDeleted) { + await deleteKibanaIndices({ client, stats, onlyTaskManager: true, log }); // delete only .kibana_task_manager* indices + kibanaTaskManagerIndexAlreadyDeleted = true; } await client.indices.create( diff --git a/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.test.ts b/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.test.ts index 0e04d6b9ba799..fbd351cea63a9 100644 --- a/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.test.ts +++ b/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.test.ts @@ -21,7 +21,7 @@ describe('esArchiver: createGenerateIndexRecordsStream()', () => { await createPromiseFromStreams([ createListStream(indices), - createGenerateIndexRecordsStream(client, stats), + createGenerateIndexRecordsStream({ client, stats }), ]); expect(stats.getTestSummary()).toEqual({ @@ -40,7 +40,7 @@ describe('esArchiver: createGenerateIndexRecordsStream()', () => { await createPromiseFromStreams([ createListStream(['index1']), - createGenerateIndexRecordsStream(client, stats), + createGenerateIndexRecordsStream({ client, stats }), ]); const params = (client.indices.get as sinon.SinonSpy).args[0][0]; @@ -58,7 +58,7 @@ describe('esArchiver: createGenerateIndexRecordsStream()', () => { const indexRecords = await createPromiseFromStreams([ createListStream(['index1', 'index2', 'index3']), - createGenerateIndexRecordsStream(client, stats), + createGenerateIndexRecordsStream({ client, stats }), createConcatStream([]), ]); @@ -83,7 +83,7 @@ describe('esArchiver: createGenerateIndexRecordsStream()', () => { const indexRecords = await createPromiseFromStreams([ createListStream(['index1']), - createGenerateIndexRecordsStream(client, stats), + createGenerateIndexRecordsStream({ client, stats }), createConcatStream([]), ]); @@ -99,4 +99,51 @@ describe('esArchiver: createGenerateIndexRecordsStream()', () => { }, ]); }); + + describe('change index names', () => { + it('changes .kibana* index names if keepIndexNames is not enabled', async () => { + const stats = createStubStats(); + const client = createStubClient(['.kibana_7.16.0_001']); + + const indexRecords = await createPromiseFromStreams([ + createListStream(['.kibana_7.16.0_001']), + createGenerateIndexRecordsStream({ client, stats }), + createConcatStream([]), + ]); + + expect(indexRecords).toEqual([ + { type: 'index', value: expect.objectContaining({ index: '.kibana_1' }) }, + ]); + }); + + it('does not change non-.kibana* index names if keepIndexNames is not enabled', async () => { + const stats = createStubStats(); + const client = createStubClient(['.foo']); + + const indexRecords = await createPromiseFromStreams([ + createListStream(['.foo']), + createGenerateIndexRecordsStream({ client, stats }), + createConcatStream([]), + ]); + + expect(indexRecords).toEqual([ + { type: 'index', value: expect.objectContaining({ index: '.foo' }) }, + ]); + }); + + it('does not change .kibana* index names if keepIndexNames is enabled', async () => { + const stats = createStubStats(); + const client = createStubClient(['.kibana_7.16.0_001']); + + const indexRecords = await createPromiseFromStreams([ + createListStream(['.kibana_7.16.0_001']), + createGenerateIndexRecordsStream({ client, stats, keepIndexNames: true }), + createConcatStream([]), + ]); + + expect(indexRecords).toEqual([ + { type: 'index', value: expect.objectContaining({ index: '.kibana_7.16.0_001' }) }, + ]); + }); + }); }); diff --git a/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.ts b/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.ts index d647a4fe5f501..e3efaa2851609 100644 --- a/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.ts +++ b/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.ts @@ -11,7 +11,15 @@ import { Transform } from 'stream'; import { Stats } from '../stats'; import { ES_CLIENT_HEADERS } from '../../client_headers'; -export function createGenerateIndexRecordsStream(client: Client, stats: Stats) { +export function createGenerateIndexRecordsStream({ + client, + stats, + keepIndexNames, +}: { + client: Client; + stats: Stats; + keepIndexNames?: boolean; +}) { return new Transform({ writableObjectMode: true, readableObjectMode: true, @@ -59,9 +67,9 @@ export function createGenerateIndexRecordsStream(client: Client, stats: Stats) { this.push({ type: 'index', value: { - // always rewrite the .kibana_* index to .kibana_1 so that + // if keepIndexNames is false, rewrite the .kibana_* index to .kibana_1 so that // when it is loaded it can skip migration, if possible - index: index.startsWith('.kibana') ? '.kibana_1' : index, + index: index.startsWith('.kibana') && !keepIndexNames ? '.kibana_1' : index, settings, mappings, aliases, diff --git a/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts b/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts index 069db636c596b..eaae1de46f1e6 100644 --- a/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts +++ b/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts @@ -16,18 +16,21 @@ import { deleteIndex } from './delete_index'; import { ES_CLIENT_HEADERS } from '../../client_headers'; /** - * Deletes all indices that start with `.kibana` + * Deletes all indices that start with `.kibana`, or if onlyTaskManager==true, all indices that start with `.kibana_task_manager` */ export async function deleteKibanaIndices({ client, stats, + onlyTaskManager = false, log, }: { client: Client; stats: Stats; + onlyTaskManager?: boolean; log: ToolingLog; }) { - const indexNames = await fetchKibanaIndices(client); + const indexPattern = onlyTaskManager ? '.kibana_task_manager*' : '.kibana*'; + const indexNames = await fetchKibanaIndices(client, indexPattern); if (!indexNames.length) { return; } @@ -75,9 +78,9 @@ function isKibanaIndex(index?: string): index is string { ); } -async function fetchKibanaIndices(client: Client) { +async function fetchKibanaIndices(client: Client, indexPattern: string) { const resp = await client.cat.indices( - { index: '.kibana*', format: 'json' }, + { index: indexPattern, format: 'json' }, { headers: ES_CLIENT_HEADERS, } From ff86a51a0164737a5244699982b63b65fb00ee2d Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Wed, 10 Nov 2021 21:12:41 -0800 Subject: [PATCH 30/51] [jest] Support meta project configs (#118122) Signed-off-by: Tyler Smalley --- packages/kbn-test/src/jest/run.ts | 10 +++++++++- .../security_solution/jest.config.dev.js | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/security_solution/jest.config.dev.js diff --git a/packages/kbn-test/src/jest/run.ts b/packages/kbn-test/src/jest/run.ts index f2592500beeee..697402adf3dd1 100644 --- a/packages/kbn-test/src/jest/run.ts +++ b/packages/kbn-test/src/jest/run.ts @@ -44,6 +44,7 @@ declare global { export function runJest(configName = 'jest.config.js') { const argv = buildArgv(process.argv); + const devConfigName = 'jest.config.dev.js'; const log = new ToolingLog({ level: argv.verbose ? 'verbose' : 'info', @@ -67,18 +68,25 @@ export function runJest(configName = 'jest.config.js') { log.verbose('commonTestFiles:', commonTestFiles); let configPath; + let devConfigPath; // sets the working directory to the cwd or the common // base directory of the provided test files let wd = testFilesProvided ? commonTestFiles : cwd; + devConfigPath = resolve(wd, devConfigName); configPath = resolve(wd, configName); - while (!existsSync(configPath)) { + while (!existsSync(configPath) && !existsSync(devConfigPath)) { wd = resolve(wd, '..'); + devConfigPath = resolve(wd, devConfigName); configPath = resolve(wd, configName); } + if (existsSync(devConfigPath)) { + configPath = devConfigPath; + } + log.verbose(`no config provided, found ${configPath}`); process.argv.push('--config', configPath); diff --git a/x-pack/plugins/security_solution/jest.config.dev.js b/x-pack/plugins/security_solution/jest.config.dev.js new file mode 100644 index 0000000000000..2162d85f43367 --- /dev/null +++ b/x-pack/plugins/security_solution/jest.config.dev.js @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../', + projects: [ + '/x-pack/plugins/security_solution/*/jest.config.js', + + '/x-pack/plugins/security_solution/server/*/jest.config.js', + '/x-pack/plugins/security_solution/public/*/jest.config.js', + ], +}; From e774ece489edb74e02bbb1be09a3bfe4162fe48b Mon Sep 17 00:00:00 2001 From: Michael Dokolin Date: Thu, 11 Nov 2021 07:24:57 +0100 Subject: [PATCH 31/51] [Reporting] Fix task manager not to run tasks before Kibana is available (#118206) --- x-pack/plugins/reporting/server/core.ts | 18 +++++++++++++++++- x-pack/plugins/reporting/server/plugin.ts | 2 +- .../create_mock_reportingplugin.ts | 3 ++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/reporting/server/core.ts b/x-pack/plugins/reporting/server/core.ts index e89ba6af3e28f..bc74f5463ba33 100644 --- a/x-pack/plugins/reporting/server/core.ts +++ b/x-pack/plugins/reporting/server/core.ts @@ -7,7 +7,7 @@ import Hapi from '@hapi/hapi'; import * as Rx from 'rxjs'; -import { first, map, take } from 'rxjs/operators'; +import { filter, first, map, take } from 'rxjs/operators'; import { ScreenshotModePluginSetup } from 'src/plugins/screenshot_mode/server'; import { BasePath, @@ -17,6 +17,8 @@ import { PluginInitializerContext, SavedObjectsClientContract, SavedObjectsServiceStart, + ServiceStatusLevels, + StatusServiceSetup, UiSettingsServiceStart, } from '../../../../src/core/server'; import { PluginStart as DataPluginStart } from '../../../../src/plugins/data/server'; @@ -44,6 +46,7 @@ export interface ReportingInternalSetup { taskManager: TaskManagerSetupContract; screenshotMode: ScreenshotModePluginSetup; logger: LevelLogger; + status: StatusServiceSetup; } export interface ReportingInternalStart { @@ -111,12 +114,25 @@ export class ReportingCore { this.pluginStart$.next(startDeps); // trigger the observer this.pluginStartDeps = startDeps; // cache + await this.assertKibanaIsAvailable(); + const { taskManager } = startDeps; const { executeTask, monitorTask } = this; // enable this instance to generate reports and to monitor for pending reports await Promise.all([executeTask.init(taskManager), monitorTask.init(taskManager)]); } + private async assertKibanaIsAvailable(): Promise { + const { status } = this.getPluginSetupDeps(); + + await status.overall$ + .pipe( + filter((current) => current.level === ServiceStatusLevels.available), + first() + ) + .toPromise(); + } + /* * Blocks the caller until setup is done */ diff --git a/x-pack/plugins/reporting/server/plugin.ts b/x-pack/plugins/reporting/server/plugin.ts index 07d61ff1630fc..8969a698a8ce4 100644 --- a/x-pack/plugins/reporting/server/plugin.ts +++ b/x-pack/plugins/reporting/server/plugin.ts @@ -52,7 +52,6 @@ export class ReportingPlugin const router = http.createRouter(); const basePath = http.basePath; - reportingCore.pluginSetup({ screenshotMode, features, @@ -63,6 +62,7 @@ export class ReportingPlugin spaces, taskManager, logger: this.logger, + status: core.status, }); registerUiSettings(core); diff --git a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts index d62cc750ccfcc..c05b2c54aeabf 100644 --- a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts +++ b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts @@ -11,7 +11,7 @@ jest.mock('../browsers'); import _ from 'lodash'; import * as Rx from 'rxjs'; -import { coreMock, elasticsearchServiceMock } from 'src/core/server/mocks'; +import { coreMock, elasticsearchServiceMock, statusServiceMock } from 'src/core/server/mocks'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { dataPluginMock } from 'src/plugins/data/server/mocks'; import { FieldFormatsRegistry } from 'src/plugins/field_formats/common'; @@ -45,6 +45,7 @@ export const createMockPluginSetup = (setupMock?: any): ReportingInternalSetup = licensing: { license$: Rx.of({ isAvailable: true, isActive: true, type: 'basic' }) } as any, taskManager: taskManagerMock.createSetup(), logger: createMockLevelLogger(), + status: statusServiceMock.createSetupContract(), ...setupMock, }; }; From f555c737d0d38b38c7a85e2ac58370d7284bb6f0 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Thu, 11 Nov 2021 07:57:35 +0100 Subject: [PATCH 32/51] [Security Solution] Refactor Host isolation exceptions delete modal to use react query instead of redux (#117161) * WIP: Refactor Delete modal to not use redux * Delete middleware delete tests * Fix tests for host isolation exception delete * Add query client provider to routes * Move the query provider up to the security app component * Move out inline arrow functions to component body --- .../security_solution/public/app/app.tsx | 19 +- .../mock/endpoint/app_context_render.tsx | 11 +- .../host_isolation_exceptions/service.ts | 2 +- .../host_isolation_exceptions/store/action.ts | 20 +- .../store/middleware.test.ts | 67 ------ .../store/middleware.ts | 47 +--- .../store/reducer.ts | 17 -- .../store/selector.ts | 3 - .../view/components/delete_modal.test.tsx | 91 ++++---- .../view/components/delete_modal.tsx | 215 +++++++++--------- .../view/host_isolation_exceptions_list.tsx | 29 ++- 11 files changed, 197 insertions(+), 324 deletions(-) diff --git a/x-pack/plugins/security_solution/public/app/app.tsx b/x-pack/plugins/security_solution/public/app/app.tsx index 8abe19ed26d8d..78a340d6bbca0 100644 --- a/x-pack/plugins/security_solution/public/app/app.tsx +++ b/x-pack/plugins/security_solution/public/app/app.tsx @@ -11,6 +11,7 @@ import { Store, Action } from 'redux'; import { Provider as ReduxStoreProvider } from 'react-redux'; import { EuiErrorBoundary } from '@elastic/eui'; +import { QueryClient, QueryClientProvider } from 'react-query'; import { AppLeaveHandler, AppMountParameters } from '../../../../../src/core/public'; import { ManageUserInfo } from '../detections/components/user_info'; @@ -34,6 +35,8 @@ interface StartAppComponent { store: Store; } +const queryClient = new QueryClient(); + const StartAppComponent: FC = ({ children, history, @@ -56,13 +59,15 @@ const StartAppComponent: FC = ({ - - {children} - + + + {children} + + diff --git a/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx b/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx index 56f5dc28652aa..ed207c9d76186 100644 --- a/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx @@ -10,6 +10,7 @@ import { createMemoryHistory, MemoryHistory } from 'history'; import { render as reactRender, RenderOptions, RenderResult } from '@testing-library/react'; import { Action, Reducer, Store } from 'redux'; import { AppDeepLink } from 'kibana/public'; +import { QueryClient, QueryClientProvider } from 'react-query'; import { coreMock } from '../../../../../../../src/core/public/mocks'; import { StartPlugins, StartServices } from '../../../types'; import { depsStartMock } from './dependencies_start_mock'; @@ -85,6 +86,14 @@ const experimentalFeaturesReducer: Reducer { const AppWrapper: React.FC<{ children: React.ReactElement }> = ({ children }) => ( - {children} + {children} ); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/service.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/service.ts index 3b796d6aff0b3..2bb987271615a 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/service.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/service.ts @@ -81,7 +81,7 @@ export async function createHostIsolationExceptionItem({ }); } -export async function deleteHostIsolationExceptionItems(http: HttpStart, id: string) { +export async function deleteOneHostIsolationExceptionItem(http: HttpStart, id: string) { await ensureHostIsolationExceptionsListExists(http); return http.delete(EXCEPTION_LIST_ITEM_URL, { query: { diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/action.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/action.ts index 237868ad18c50..7a9b1dc60c445 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/action.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/action.ts @@ -5,10 +5,7 @@ * 2.0. */ -import { - ExceptionListItemSchema, - UpdateExceptionListItemSchema, -} from '@kbn/securitysolution-io-ts-list-types'; +import { UpdateExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; import { Action } from 'redux'; import { HostIsolationExceptionsPageState } from '../types'; @@ -31,16 +28,7 @@ export type HostIsolationExceptionsCreateEntry = Action<'hostIsolationExceptions payload: HostIsolationExceptionsPageState['form']['entry']; }; -export type HostIsolationExceptionsDeleteItem = Action<'hostIsolationExceptionsMarkToDelete'> & { - payload?: ExceptionListItemSchema; -}; - -export type HostIsolationExceptionsSubmitDelete = Action<'hostIsolationExceptionsSubmitDelete'>; - -export type HostIsolationExceptionsDeleteStatusChanged = - Action<'hostIsolationExceptionsDeleteStatusChanged'> & { - payload: HostIsolationExceptionsPageState['deletion']['status']; - }; +export type HostIsolationExceptionsRefreshList = Action<'hostIsolationExceptionsRefreshList'>; export type HostIsolationExceptionsMarkToEdit = Action<'hostIsolationExceptionsMarkToEdit'> & { payload: { @@ -56,9 +44,7 @@ export type HostIsolationExceptionsPageAction = | HostIsolationExceptionsPageDataChanged | HostIsolationExceptionsCreateEntry | HostIsolationExceptionsFormStateChanged - | HostIsolationExceptionsDeleteItem - | HostIsolationExceptionsSubmitDelete - | HostIsolationExceptionsDeleteStatusChanged + | HostIsolationExceptionsRefreshList | HostIsolationExceptionsFormEntryChanged | HostIsolationExceptionsMarkToEdit | HostIsolationExceptionsSubmitEdit; diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.test.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.test.ts index 878c17a1a2757..a59a289f79be5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.test.ts @@ -25,7 +25,6 @@ import { } from '../../../state'; import { createHostIsolationExceptionItem, - deleteHostIsolationExceptionItems, getHostIsolationExceptionItems, getOneHostIsolationExceptionItem, updateOneHostIsolationExceptionItem, @@ -39,7 +38,6 @@ import { getListFetchError } from './selector'; jest.mock('../service'); const getHostIsolationExceptionItemsMock = getHostIsolationExceptionItems as jest.Mock; -const deleteHostIsolationExceptionItemsMock = deleteHostIsolationExceptionItems as jest.Mock; const createHostIsolationExceptionItemMock = createHostIsolationExceptionItem as jest.Mock; const getOneHostIsolationExceptionItemMock = getOneHostIsolationExceptionItem as jest.Mock; const updateOneHostIsolationExceptionItemMock = updateOneHostIsolationExceptionItem as jest.Mock; @@ -319,69 +317,4 @@ describe('Host isolation exceptions middleware', () => { await waiter; }); }); - - describe('When deleting an item from host isolation exceptions', () => { - beforeEach(() => { - deleteHostIsolationExceptionItemsMock.mockReset(); - deleteHostIsolationExceptionItemsMock.mockReturnValue(undefined); - getHostIsolationExceptionItemsMock.mockReset(); - getHostIsolationExceptionItemsMock.mockImplementation(getFoundExceptionListItemSchemaMock); - store.dispatch({ - type: 'hostIsolationExceptionsMarkToDelete', - payload: { - id: '1', - }, - }); - }); - - it('should call the delete exception API when a delete is submitted and advertise a loading status', async () => { - const waiter = Promise.all([ - // delete loading action - spyMiddleware.waitForAction('hostIsolationExceptionsDeleteStatusChanged', { - validate({ payload }) { - return isLoadingResourceState(payload); - }, - }), - // delete finished action - spyMiddleware.waitForAction('hostIsolationExceptionsDeleteStatusChanged', { - validate({ payload }) { - return isLoadedResourceState(payload); - }, - }), - ]); - store.dispatch({ - type: 'hostIsolationExceptionsSubmitDelete', - }); - await waiter; - expect(deleteHostIsolationExceptionItemsMock).toHaveBeenLastCalledWith( - fakeCoreStart.http, - '1' - ); - }); - - it('should dispatch a failure if the API returns an error', async () => { - deleteHostIsolationExceptionItemsMock.mockRejectedValue({ - body: { message: 'error message', statusCode: 500, error: 'Internal Server Error' }, - }); - store.dispatch({ - type: 'hostIsolationExceptionsSubmitDelete', - }); - await spyMiddleware.waitForAction('hostIsolationExceptionsDeleteStatusChanged', { - validate({ payload }) { - return isFailedResourceState(payload); - }, - }); - }); - - it('should reload the host isolation exception lists after delete', async () => { - store.dispatch({ - type: 'hostIsolationExceptionsSubmitDelete', - }); - await spyMiddleware.waitForAction('hostIsolationExceptionsPageDataChanged', { - validate({ payload }) { - return isLoadingResourceState(payload); - }, - }); - }); - }); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.ts index 3eca607f0c747..f4e49b1ea02da 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/middleware.ts @@ -26,14 +26,13 @@ import { asStaleResourceState, } from '../../../state/async_resource_builders'; import { - deleteHostIsolationExceptionItems, getHostIsolationExceptionItems, createHostIsolationExceptionItem, getOneHostIsolationExceptionItem, updateOneHostIsolationExceptionItem, } from '../service'; import { HostIsolationExceptionsPageState } from '../types'; -import { getCurrentListPageDataState, getCurrentLocation, getItemToDelete } from './selector'; +import { getCurrentListPageDataState, getCurrentLocation } from './selector'; import { HostIsolationExceptionsPageAction } from './action'; export const SEARCHABLE_FIELDS: Readonly = [`name`, `description`, `entries.value`]; @@ -52,12 +51,12 @@ export const createHostIsolationExceptionsPageMiddleware = ( loadHostIsolationExceptionsList(store, coreStart.http); } - if (action.type === 'hostIsolationExceptionsCreateEntry') { - createHostIsolationException(store, coreStart.http); + if (action.type === 'hostIsolationExceptionsRefreshList') { + loadHostIsolationExceptionsList(store, coreStart.http); } - if (action.type === 'hostIsolationExceptionsSubmitDelete') { - deleteHostIsolationExceptionsItem(store, coreStart.http); + if (action.type === 'hostIsolationExceptionsCreateEntry') { + createHostIsolationException(store, coreStart.http); } if (action.type === 'hostIsolationExceptionsMarkToEdit') { @@ -156,42 +155,6 @@ function isHostIsolationExceptionsPage(location: Immutable) { ); } -async function deleteHostIsolationExceptionsItem( - store: ImmutableMiddlewareAPI< - HostIsolationExceptionsPageState, - HostIsolationExceptionsPageAction - >, - http: HttpSetup -) { - const { dispatch } = store; - const itemToDelete = getItemToDelete(store.getState()); - if (itemToDelete === undefined) { - return; - } - - try { - dispatch({ - type: 'hostIsolationExceptionsDeleteStatusChanged', - payload: { - type: 'LoadingResourceState', - }, - }); - - await deleteHostIsolationExceptionItems(http, itemToDelete.id); - - dispatch({ - type: 'hostIsolationExceptionsDeleteStatusChanged', - payload: createLoadedResourceState(itemToDelete), - }); - loadHostIsolationExceptionsList(store, http); - } catch (error) { - dispatch({ - type: 'hostIsolationExceptionsDeleteStatusChanged', - payload: createFailedResourceState(error.body ?? error), - }); - } -} - async function loadHostIsolationExceptionsItem( store: ImmutableMiddlewareAPI< HostIsolationExceptionsPageState, diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/reducer.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/reducer.ts index 77a1c248d0cf0..d89e8abef5aae 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/reducer.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/reducer.ts @@ -73,23 +73,6 @@ export const hostIsolationExceptionsPageReducer: StateReducer = ( } case 'userChangedUrl': return userChangedUrl(state, action); - case 'hostIsolationExceptionsMarkToDelete': { - return { - ...state, - deletion: { - item: action.payload, - status: createUninitialisedResourceState(), - }, - }; - } - case 'hostIsolationExceptionsDeleteStatusChanged': - return { - ...state, - deletion: { - ...state.deletion, - status: action.payload, - }, - }; } return state; }; diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/selector.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/selector.ts index 996978f96fcb5..9e79637259941 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/selector.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/store/selector.ts @@ -93,9 +93,6 @@ export const showDeleteModal: HostIsolationExceptionsSelector = createS } ); -export const getItemToDelete: HostIsolationExceptionsSelector = - createSelector(getDeletionState, ({ item }) => item); - export const isDeletionInProgress: HostIsolationExceptionsSelector = createSelector( getDeletionState, ({ status }) => { diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.test.tsx index 9cca87bf61d6a..a133801bf356c 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.test.tsx @@ -5,38 +5,34 @@ * 2.0. */ import React from 'react'; -import { act } from '@testing-library/react'; import { AppContextTestRender, createAppRootMockRenderer, } from '../../../../../common/mock/endpoint'; import { HostIsolationExceptionDeleteModal } from './delete_modal'; -import { isFailedResourceState, isLoadedResourceState } from '../../../../state'; -import { getHostIsolationExceptionItems, deleteHostIsolationExceptionItems } from '../../service'; +import { deleteOneHostIsolationExceptionItem } from '../../service'; import { getExceptionListItemSchemaMock } from '../../../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; -import { fireEvent } from '@testing-library/dom'; +import { waitFor } from '@testing-library/dom'; +import userEvent from '@testing-library/user-event'; jest.mock('../../service'); -const getHostIsolationExceptionItemsMock = getHostIsolationExceptionItems as jest.Mock; -const deleteHostIsolationExceptionItemsMock = deleteHostIsolationExceptionItems as jest.Mock; +const deleteOneHostIsolationExceptionItemMock = deleteOneHostIsolationExceptionItem as jest.Mock; describe('When on the host isolation exceptions delete modal', () => { let render: () => ReturnType; let renderResult: ReturnType; - let waitForAction: AppContextTestRender['middlewareSpy']['waitForAction']; let coreStart: AppContextTestRender['coreStart']; + let onCancel: (forceRefresh?: boolean) => void; beforeEach(() => { - const itemToDelete = getExceptionListItemSchemaMock(); - getHostIsolationExceptionItemsMock.mockReset(); - deleteHostIsolationExceptionItemsMock.mockReset(); const mockedContext = createAppRootMockRenderer(); - mockedContext.store.dispatch({ - type: 'hostIsolationExceptionsMarkToDelete', - payload: itemToDelete, - }); - render = () => (renderResult = mockedContext.render()); - waitForAction = mockedContext.middlewareSpy.waitForAction; + const itemToDelete = getExceptionListItemSchemaMock(); + deleteOneHostIsolationExceptionItemMock.mockReset(); + onCancel = jest.fn(); + render = () => + (renderResult = mockedContext.render( + + )); ({ coreStart } = mockedContext); }); @@ -51,6 +47,13 @@ describe('When on the host isolation exceptions delete modal', () => { it('should disable the buttons when confirm is pressed and show loading', async () => { render(); + // fake a delay on a response + deleteOneHostIsolationExceptionItemMock.mockImplementationOnce(() => { + return new Promise((resolve) => { + setTimeout(resolve, 300); + }); + }); + const submitButton = renderResult.baseElement.querySelector( '[data-test-subj="hostIsolationExceptionsDeleteModalConfirmButton"]' ) as HTMLButtonElement; @@ -59,77 +62,65 @@ describe('When on the host isolation exceptions delete modal', () => { '[data-test-subj="hostIsolationExceptionsDeleteModalConfirmButton"]' ) as HTMLButtonElement; - act(() => { - fireEvent.click(submitButton); - }); + userEvent.click(submitButton); + + // wait for the mock API to be called + await waitFor(expect(deleteOneHostIsolationExceptionItemMock).toHaveBeenCalled); expect(submitButton.disabled).toBe(true); expect(cancelButton.disabled).toBe(true); expect(submitButton.querySelector('.euiLoadingSpinner')).not.toBeNull(); }); - it('should clear the item marked to delete when cancel is pressed', async () => { + it('should call the onCancel callback when cancel is pressed', async () => { render(); const cancelButton = renderResult.baseElement.querySelector( '[data-test-subj="hostIsolationExceptionsDeleteModalConfirmButton"]' ) as HTMLButtonElement; - const waiter = waitForAction('hostIsolationExceptionsMarkToDelete', { - validate: ({ payload }) => { - return payload === undefined; - }, + userEvent.click(cancelButton); + await waitFor(() => { + expect(onCancel).toHaveBeenCalledTimes(1); }); - - act(() => { - fireEvent.click(cancelButton); - }); - expect(await waiter).toBeTruthy(); }); - it('should show success toast after the delete is completed', async () => { + it('should show success toast after the delete is completed and call onCancel with forceRefresh', async () => { + deleteOneHostIsolationExceptionItemMock.mockResolvedValue({}); render(); - const updateCompleted = waitForAction('hostIsolationExceptionsDeleteStatusChanged', { - validate(action) { - return isLoadedResourceState(action.payload); - }, - }); const submitButton = renderResult.baseElement.querySelector( '[data-test-subj="hostIsolationExceptionsDeleteModalConfirmButton"]' ) as HTMLButtonElement; - await act(async () => { - fireEvent.click(submitButton); - await updateCompleted; - }); + userEvent.click(submitButton); + + // wait for the mock API to be called + await waitFor(expect(deleteOneHostIsolationExceptionItemMock).toHaveBeenCalled); expect(coreStart.notifications.toasts.addSuccess).toHaveBeenCalledWith( '"some name" has been removed from the Host isolation exceptions list.' ); + expect(onCancel).toHaveBeenCalledWith(true); }); - it('should show error toast if error is encountered', async () => { - deleteHostIsolationExceptionItemsMock.mockRejectedValue( + it('should show error toast if error is encountered and call onCancel with forceRefresh', async () => { + deleteOneHostIsolationExceptionItemMock.mockRejectedValue( new Error("That's not true. That's impossible") ); render(); - const updateFailure = waitForAction('hostIsolationExceptionsDeleteStatusChanged', { - validate(action) { - return isFailedResourceState(action.payload); - }, - }); const submitButton = renderResult.baseElement.querySelector( '[data-test-subj="hostIsolationExceptionsDeleteModalConfirmButton"]' ) as HTMLButtonElement; - await act(async () => { - fireEvent.click(submitButton); - await updateFailure; - }); + userEvent.click(submitButton); + + // wait for the mock API to be called + await waitFor(expect(deleteOneHostIsolationExceptionItemMock).toHaveBeenCalled); expect(coreStart.notifications.toasts.addDanger).toHaveBeenCalledWith( 'Unable to remove "some name" from the Host isolation exceptions list. Reason: That\'s not true. That\'s impossible' ); + expect(onCancel).toHaveBeenCalledWith(true); }); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.tsx index 51e0ab5a5a154..0b9319580a443 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { memo, useCallback, useEffect } from 'react'; +import React, { memo } from 'react'; import { EuiButton, EuiButtonEmpty, @@ -17,125 +17,122 @@ import { EuiText, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { useDispatch } from 'react-redux'; -import { Dispatch } from 'redux'; import { i18n } from '@kbn/i18n'; -import { useToasts } from '../../../../../common/lib/kibana'; -import { useHostIsolationExceptionsSelector } from '../hooks'; -import { - getDeleteError, - getItemToDelete, - isDeletionInProgress, - wasDeletionSuccessful, -} from '../../store/selector'; -import { HostIsolationExceptionsPageAction } from '../../store/action'; - -export const HostIsolationExceptionDeleteModal = memo<{}>(() => { - const dispatch = useDispatch>(); - const toasts = useToasts(); +import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { useMutation } from 'react-query'; +import { useHttp, useToasts } from '../../../../../common/lib/kibana'; +import { deleteOneHostIsolationExceptionItem } from '../../service'; - const isDeleting = useHostIsolationExceptionsSelector(isDeletionInProgress); - const exception = useHostIsolationExceptionsSelector(getItemToDelete); - const wasDeleted = useHostIsolationExceptionsSelector(wasDeletionSuccessful); - const deleteError = useHostIsolationExceptionsSelector(getDeleteError); +export const HostIsolationExceptionDeleteModal = memo( + ({ + item, + onCancel, + }: { + item: ExceptionListItemSchema; + onCancel: (forceRefresh?: boolean) => void; + }) => { + const toasts = useToasts(); + const http = useHttp(); - const onCancel = useCallback(() => { - dispatch({ type: 'hostIsolationExceptionsMarkToDelete', payload: undefined }); - }, [dispatch]); + const mutation = useMutation( + () => { + return deleteOneHostIsolationExceptionItem(http, item.id); + }, + { + onError: (error: Error) => { + toasts.addDanger( + i18n.translate( + 'xpack.securitySolution.hostIsolationExceptions.deletionDialog.deleteFailure', + { + defaultMessage: + 'Unable to remove "{name}" from the Host isolation exceptions list. Reason: {message}', + values: { name: item?.name, message: error.message }, + } + ) + ); + onCancel(true); + }, + onSuccess: () => { + toasts.addSuccess( + i18n.translate( + 'xpack.securitySolution.hostIsolationExceptions.deletionDialog.deleteSuccess', + { + defaultMessage: + '"{name}" has been removed from the Host isolation exceptions list.', + values: { name: item?.name }, + } + ) + ); + onCancel(true); + }, + } + ); - const onConfirm = useCallback(() => { - dispatch({ type: 'hostIsolationExceptionsSubmitDelete' }); - }, [dispatch]); + const handleConfirmButton = () => { + mutation.mutate(); + }; - // Show toast for success - useEffect(() => { - if (wasDeleted) { - toasts.addSuccess( - i18n.translate( - 'xpack.securitySolution.hostIsolationExceptions.deletionDialog.deleteSuccess', - { - defaultMessage: '"{name}" has been removed from the Host isolation exceptions list.', - values: { name: exception?.name }, - } - ) - ); + const handleCancelButton = () => { + onCancel(); + }; - dispatch({ type: 'hostIsolationExceptionsMarkToDelete', payload: undefined }); - } - }, [dispatch, exception?.name, toasts, wasDeleted]); - - // show toast for failures - useEffect(() => { - if (deleteError) { - toasts.addDanger( - i18n.translate( - 'xpack.securitySolution.hostIsolationExceptions.deletionDialog.deleteFailure', - { - defaultMessage: - 'Unable to remove "{name}" from the Host isolation exceptions list. Reason: {message}', - values: { name: exception?.name, message: deleteError.message }, - } - ) - ); - } - }, [deleteError, exception?.name, toasts]); + return ( + onCancel()}> + + + + + - return ( - - - - - - + + +

    + {item?.name} }} + /> +

    +

    + +

    +
    +
    - - -

    + + {exception?.name} }} + id="xpack.securitySolution.hostIsolationExceptions.deletionDialog.cancel" + defaultMessage="Cancel" /> -

    -

    + + + -

    -
    -
    - - - - - - - - - - -
    - ); -}); + + +
    + ); + } +); HostIsolationExceptionDeleteModal.displayName = 'HostIsolationExceptionDeleteModal'; diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx index f7429c213d2d5..14a5bae009988 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx @@ -7,15 +7,14 @@ import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; import { i18n } from '@kbn/i18n'; -import React, { Dispatch, useCallback, useEffect } from 'react'; +import React, { Dispatch, useCallback, useEffect, useState } from 'react'; import { EuiButton, EuiText, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { useDispatch } from 'react-redux'; import { useHistory } from 'react-router-dom'; +import { useDispatch } from 'react-redux'; import { ExceptionItem } from '../../../../common/components/exceptions/viewer/exception_item'; import { getCurrentLocation, - getItemToDelete, getListFetchError, getListIsLoading, getListItems, @@ -32,7 +31,6 @@ import { AdministrationListPage } from '../../../components/administration_list_ import { SearchExceptions } from '../../../components/search_exceptions'; import { ArtifactEntryCard, ArtifactEntryCardProps } from '../../../components/artifact_entry_card'; import { HostIsolationExceptionsEmptyState } from './components/empty'; -import { HostIsolationExceptionsPageAction } from '../store/action'; import { HostIsolationExceptionDeleteModal } from './components/delete_modal'; import { HostIsolationExceptionsFormFlyout } from './components/form_flyout'; import { @@ -41,6 +39,7 @@ import { } from './components/translations'; import { getEndpointListPath } from '../../../common/routing'; import { useEndpointPrivileges } from '../../../../common/components/user_privileges/endpoint'; +import { HostIsolationExceptionsPageAction } from '../store/action'; type HostIsolationExceptionPaginatedContent = PaginatedContentProps< Immutable, @@ -55,8 +54,10 @@ export const HostIsolationExceptionsList = () => { const fetchError = useHostIsolationExceptionsSelector(getListFetchError); const location = useHostIsolationExceptionsSelector(getCurrentLocation); const dispatch = useDispatch>(); - const itemToDelete = useHostIsolationExceptionsSelector(getItemToDelete); const navigateCallback = useHostIsolationExceptionsNavigateCallback(); + + const [itemToDelete, setItemToDelete] = useState(null); + const history = useHistory(); const privileges = useEndpointPrivileges(); const showFlyout = privileges.canIsolateHost && !!location.show; @@ -90,10 +91,7 @@ export const HostIsolationExceptionsList = () => { const deleteAction = { icon: 'trash', onClick: () => { - dispatch({ - type: 'hostIsolationExceptionsMarkToDelete', - payload: element, - }); + setItemToDelete(element); }, 'data-test-subj': 'deleteHostIsolationException', children: DELETE_HOST_ISOLATION_EXCEPTION_LABEL, @@ -125,6 +123,15 @@ export const HostIsolationExceptionsList = () => { [navigateCallback] ); + const handleCloseDeleteDialog = (forceRefresh: boolean = false) => { + if (forceRefresh) { + dispatch({ + type: 'hostIsolationExceptionsRefreshList', + }); + } + setItemToDelete(null); + }; + return ( { > {showFlyout && } - {itemToDelete ? : null} + {itemToDelete ? ( + + ) : null} {hasDataToShow ? ( <> From b87852071bb92d7097f237735bae0fcbecdb149d Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 11 Nov 2021 08:26:48 +0100 Subject: [PATCH 33/51] [Lens] fix passing 0 as static value (#118032) * [Lens] fix passing 0 as static value * allow computed static_value to be passed * Update x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.tsx Co-authored-by: Marco Liberati * ci fix Co-authored-by: Marco Liberati --- .../indexpattern.test.ts | 2 +- .../definitions/static_value.test.tsx | 30 +++++++++++++++++++ .../operations/definitions/static_value.tsx | 4 +-- .../reference_line_helpers.test.ts | 26 ++++++++++++++++ .../reference_line_helpers.tsx | 15 +++++----- 5 files changed, 66 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts index 1dfc7d40f6f3e..5a405bb2328eb 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts @@ -1696,7 +1696,7 @@ describe('IndexPattern Data Source', () => { isBucketed: false, label: 'Static value: 0', operationType: 'static_value', - params: { value: 0 }, + params: { value: '0' }, references: [], scale: 'ratio', }, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx index 1c574fe69611c..816324f9f8fb5 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx @@ -338,6 +338,36 @@ describe('static_value', () => { expect(input.prop('value')).toEqual('23'); }); + it('should allow 0 as initial value', () => { + const updateLayerSpy = jest.fn(); + const zeroLayer = { + ...layer, + columns: { + ...layer.columns, + col2: { + ...layer.columns.col2, + operationType: 'static_value', + references: [], + params: { + value: '0', + }, + }, + }, + } as IndexPatternLayer; + const instance = shallow( + + ); + + const input = instance.find('[data-test-subj="lns-indexPattern-static_value-input"]'); + expect(input.prop('value')).toEqual('0'); + }); + it('should update state on change', async () => { const updateLayerSpy = jest.fn(); const instance = mount( diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx index b759ebe46fb33..b66092e8a48c3 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx @@ -95,7 +95,7 @@ export const staticValueOperation: OperationDefinition< arguments: { id: [columnId], name: [label || defaultLabel], - expression: [isValidNumber(params.value) ? params.value! : String(defaultValue)], + expression: [String(isValidNumber(params.value) ? params.value! : defaultValue)], }, }, ]; @@ -118,7 +118,7 @@ export const staticValueOperation: OperationDefinition< operationType: 'static_value', isBucketed: false, scale: 'ratio', - params: { ...previousParams, value: previousParams.value ?? String(defaultValue) }, + params: { ...previousParams, value: String(previousParams.value ?? defaultValue) }, references: [], }; }, diff --git a/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.test.ts b/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.test.ts index 42caca7fa2e09..9f48b8c8c36e4 100644 --- a/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.test.ts @@ -120,6 +120,32 @@ describe('reference_line helpers', () => { ).toBe(100); }); + it('should return 0 as result of calculation', () => { + expect( + getStaticValue( + [ + { + layerId: 'id-a', + seriesType: 'area', + layerType: 'data', + accessors: ['a'], + yConfig: [{ forAccessor: 'a', axisMode: 'right' }], + } as XYLayerConfig, + ], + 'yRight', + { + activeData: getActiveData([ + { + id: 'id-a', + rows: [{ a: -30 }, { a: 10 }], + }, + ]), + }, + hasAllNumberHistogram + ) + ).toBe(0); + }); + it('should work for no yConfig defined and fallback to left axis', () => { expect( getStaticValue( diff --git a/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.tsx b/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.tsx index 53a2d4bcc7222..127bf02b81f89 100644 --- a/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.tsx @@ -104,15 +104,14 @@ export function getStaticValue( ) { return fallbackValue; } - return ( - computeStaticValueForGroup( - filteredLayers, - accessors, - activeData, - groupId !== 'x', // histogram axis should compute the min based on the current data - groupId !== 'x' - ) || fallbackValue + const computedValue = computeStaticValueForGroup( + filteredLayers, + accessors, + activeData, + groupId !== 'x', // histogram axis should compute the min based on the current data + groupId !== 'x' ); + return computedValue ?? fallbackValue; } function getAccessorCriteriaForGroup( From 29b08ecc7801658893a786dead5784b4324dc107 Mon Sep 17 00:00:00 2001 From: Tim Roes Date: Thu, 11 Nov 2021 09:37:17 +0100 Subject: [PATCH 34/51] Only set ignored_throttled when required (#118185) --- x-pack/plugins/graph/server/routes/search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/graph/server/routes/search.ts b/x-pack/plugins/graph/server/routes/search.ts index 2f792dd399ccf..92f3d7a02b072 100644 --- a/x-pack/plugins/graph/server/routes/search.ts +++ b/x-pack/plugins/graph/server/routes/search.ts @@ -49,7 +49,7 @@ export function registerSearchRoute({ index: request.body.index, body: request.body.body, track_total_hits: true, - ignore_throttled: !includeFrozen, + ...(includeFrozen ? { ignore_throttled: false } : {}), }) ).body, }, From 9c0016f055ade27cccb672cd6fa869a443c21b75 Mon Sep 17 00:00:00 2001 From: Julia Bardi <90178898+juliaElastic@users.noreply.github.com> Date: Thu, 11 Nov 2021 09:54:49 +0100 Subject: [PATCH 35/51] [Fleet] Package telemetry (#117978) * renamed upgrade event * added package update events * fixed tests * fixed tests * fixed for async flow * fixed jest test * added unit tests * changed to logger.debug in sender.ts --- .../services/epm/packages/install.test.ts | 252 ++++++++++++++++++ .../server/services/epm/packages/install.ts | 66 ++++- .../server/services/package_policy.test.ts | 2 +- .../fleet/server/services/package_policy.ts | 22 +- ...e_usage.test.ts => upgrade_sender.test.ts} | 24 +- .../{upgrade_usage.ts => upgrade_sender.ts} | 30 ++- .../fleet/server/telemetry/sender.test.ts | 26 +- .../plugins/fleet/server/telemetry/sender.ts | 4 +- .../plugins/fleet/server/telemetry/types.ts | 4 +- 9 files changed, 389 insertions(+), 41 deletions(-) create mode 100644 x-pack/plugins/fleet/server/services/epm/packages/install.test.ts rename x-pack/plugins/fleet/server/services/{upgrade_usage.test.ts => upgrade_sender.test.ts} (73%) rename x-pack/plugins/fleet/server/services/{upgrade_usage.ts => upgrade_sender.ts} (69%) diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts new file mode 100644 index 0000000000000..a9bb235c22cb8 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts @@ -0,0 +1,252 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { savedObjectsClientMock } from 'src/core/server/mocks'; + +import type { ElasticsearchClient } from 'kibana/server'; + +import * as Registry from '../registry'; + +import { sendTelemetryEvents } from '../../upgrade_sender'; + +import { licenseService } from '../../license'; + +import { installPackage } from './install'; +import * as install from './_install_package'; +import * as obj from './index'; + +jest.mock('../../app_context', () => { + return { + appContextService: { + getLogger: jest.fn(() => { + return { error: jest.fn(), debug: jest.fn(), warn: jest.fn() }; + }), + getTelemetryEventsSender: jest.fn(), + }, + }; +}); +jest.mock('./index'); +jest.mock('../registry'); +jest.mock('../../upgrade_sender'); +jest.mock('../../license'); +jest.mock('../../upgrade_sender'); +jest.mock('./cleanup'); +jest.mock('./_install_package', () => { + return { + _installPackage: jest.fn(() => Promise.resolve()), + }; +}); +jest.mock('../kibana/index_pattern/install', () => { + return { + installIndexPatterns: jest.fn(() => Promise.resolve()), + }; +}); +jest.mock('../archive', () => { + return { + parseAndVerifyArchiveEntries: jest.fn(() => + Promise.resolve({ packageInfo: { name: 'apache', version: '1.3.0' } }) + ), + unpackBufferToCache: jest.fn(), + setPackageInfo: jest.fn(), + }; +}); + +describe('install', () => { + beforeEach(() => { + jest.spyOn(Registry, 'splitPkgKey').mockImplementation((pkgKey: string) => { + const [pkgName, pkgVersion] = pkgKey.split('-'); + return { pkgName, pkgVersion }; + }); + jest + .spyOn(Registry, 'fetchFindLatestPackage') + .mockImplementation(() => Promise.resolve({ version: '1.3.0' } as any)); + jest + .spyOn(Registry, 'getRegistryPackage') + .mockImplementation(() => Promise.resolve({ packageInfo: { license: 'basic' } } as any)); + }); + + describe('registry', () => { + it('should send telemetry on install failure, out of date', async () => { + await installPackage({ + installSource: 'registry', + pkgkey: 'apache-1.1.0', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, + }); + + expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { + currentVersion: 'not_installed', + dryRun: false, + errorMessage: 'apache-1.1.0 is out-of-date and cannot be installed or updated', + eventType: 'package-install', + installType: 'install', + newVersion: '1.1.0', + packageName: 'apache', + status: 'failure', + }); + }); + + it('should send telemetry on install failure, license error', async () => { + jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(false); + await installPackage({ + installSource: 'registry', + pkgkey: 'apache-1.3.0', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, + }); + + expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { + currentVersion: 'not_installed', + dryRun: false, + errorMessage: 'Requires basic license', + eventType: 'package-install', + installType: 'install', + newVersion: '1.3.0', + packageName: 'apache', + status: 'failure', + }); + }); + + it('should send telemetry on install success', async () => { + jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); + await installPackage({ + installSource: 'registry', + pkgkey: 'apache-1.3.0', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, + }); + + expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { + currentVersion: 'not_installed', + dryRun: false, + eventType: 'package-install', + installType: 'install', + newVersion: '1.3.0', + packageName: 'apache', + status: 'success', + }); + }); + + it('should send telemetry on update success', async () => { + jest + .spyOn(obj, 'getInstallationObject') + .mockImplementationOnce(() => Promise.resolve({ attributes: { version: '1.2.0' } } as any)); + jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); + await installPackage({ + installSource: 'registry', + pkgkey: 'apache-1.3.0', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, + }); + + expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { + currentVersion: '1.2.0', + dryRun: false, + eventType: 'package-install', + installType: 'update', + newVersion: '1.3.0', + packageName: 'apache', + status: 'success', + }); + }); + + it('should send telemetry on install failure, async error', async () => { + jest + .spyOn(install, '_installPackage') + .mockImplementation(() => Promise.reject(new Error('error'))); + jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); + await installPackage({ + installSource: 'registry', + pkgkey: 'apache-1.3.0', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, + }); + + expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { + currentVersion: 'not_installed', + dryRun: false, + errorMessage: 'error', + eventType: 'package-install', + installType: 'install', + newVersion: '1.3.0', + packageName: 'apache', + status: 'failure', + }); + }); + }); + + describe('upload', () => { + it('should send telemetry on install failure', async () => { + jest + .spyOn(obj, 'getInstallationObject') + .mockImplementationOnce(() => Promise.resolve({ attributes: { version: '1.2.0' } } as any)); + await installPackage({ + installSource: 'upload', + archiveBuffer: {} as Buffer, + contentType: '', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, + }); + + expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { + currentVersion: '1.2.0', + dryRun: false, + errorMessage: + 'Package upload only supports fresh installations. Package apache is already installed, please uninstall first.', + eventType: 'package-install', + installType: 'update', + newVersion: '1.3.0', + packageName: 'apache', + status: 'failure', + }); + }); + + it('should send telemetry on install success', async () => { + await installPackage({ + installSource: 'upload', + archiveBuffer: {} as Buffer, + contentType: '', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, + }); + + expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { + currentVersion: 'not_installed', + dryRun: false, + eventType: 'package-install', + installType: 'install', + newVersion: '1.3.0', + packageName: 'apache', + status: 'success', + }); + }); + + it('should send telemetry on install failure, async error', async () => { + jest + .spyOn(install, '_installPackage') + .mockImplementation(() => Promise.reject(new Error('error'))); + await installPackage({ + installSource: 'upload', + archiveBuffer: {} as Buffer, + contentType: '', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, + }); + + expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { + currentVersion: 'not_installed', + dryRun: false, + errorMessage: 'error', + eventType: 'package-install', + installType: 'install', + newVersion: '1.3.0', + packageName: 'apache', + status: 'failure', + }); + }); + }); +}); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install.ts b/x-pack/plugins/fleet/server/services/epm/packages/install.ts index f57965614adc6..42f4663dc21e3 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install.ts @@ -41,6 +41,9 @@ import { toAssetReference } from '../kibana/assets/install'; import type { ArchiveAsset } from '../kibana/assets/install'; import { installIndexPatterns } from '../kibana/index_pattern/install'; +import type { PackageUpdateEvent } from '../../upgrade_sender'; +import { sendTelemetryEvents, UpdateEventType } from '../../upgrade_sender'; + import { isUnremovablePackage, getInstallation, getInstallationObject } from './index'; import { removeInstallation } from './remove'; import { getPackageSavedObjects } from './get'; @@ -203,6 +206,26 @@ interface InstallRegistryPackageParams { force?: boolean; } +function getTelemetryEvent(pkgName: string, pkgVersion: string): PackageUpdateEvent { + return { + packageName: pkgName, + currentVersion: 'unknown', + newVersion: pkgVersion, + status: 'failure', + dryRun: false, + eventType: UpdateEventType.PACKAGE_INSTALL, + installType: 'unknown', + }; +} + +function sendEvent(telemetryEvent: PackageUpdateEvent) { + sendTelemetryEvents( + appContextService.getLogger(), + appContextService.getTelemetryEventsSender(), + telemetryEvent + ); +} + async function installPackageFromRegistry({ savedObjectsClient, pkgkey, @@ -216,6 +239,8 @@ async function installPackageFromRegistry({ // if an error happens during getInstallType, report that we don't know let installType: InstallType = 'unknown'; + const telemetryEvent: PackageUpdateEvent = getTelemetryEvent(pkgName, pkgVersion); + try { // get the currently installed package const installedPkg = await getInstallationObject({ savedObjectsClient, pkgName }); @@ -248,6 +273,9 @@ async function installPackageFromRegistry({ } } + telemetryEvent.installType = installType; + telemetryEvent.currentVersion = installedPkg?.attributes.version || 'not_installed'; + // if the requested version is out-of-date of the latest package version, check if we allow it // if we don't allow it, return an error if (semverLt(pkgVersion, latestPackage.version)) { @@ -267,7 +295,12 @@ async function installPackageFromRegistry({ const { paths, packageInfo } = await Registry.getRegistryPackage(pkgName, pkgVersion); if (!licenseService.hasAtLeast(packageInfo.license || 'basic')) { - return { error: new Error(`Requires ${packageInfo.license} license`), installType }; + const err = new Error(`Requires ${packageInfo.license} license`); + sendEvent({ + ...telemetryEvent, + errorMessage: err.message, + }); + return { error: err, installType }; } // try installing the package, if there was an error, call error handler and rethrow @@ -287,6 +320,10 @@ async function installPackageFromRegistry({ pkgName: packageInfo.name, currentVersion: packageInfo.version, }); + sendEvent({ + ...telemetryEvent, + status: 'success', + }); return { assets, status: 'installed', installType }; }) .catch(async (err: Error) => { @@ -299,9 +336,17 @@ async function installPackageFromRegistry({ installedPkg, esClient, }); + sendEvent({ + ...telemetryEvent, + errorMessage: err.message, + }); return { error: err, installType }; }); } catch (e) { + sendEvent({ + ...telemetryEvent, + errorMessage: e.message, + }); return { error: e, installType, @@ -324,6 +369,7 @@ async function installPackageByUpload({ }: InstallUploadedArchiveParams): Promise { // if an error happens during getInstallType, report that we don't know let installType: InstallType = 'unknown'; + const telemetryEvent: PackageUpdateEvent = getTelemetryEvent('', ''); try { const { packageInfo } = await parseAndVerifyArchiveEntries(archiveBuffer, contentType); @@ -333,6 +379,12 @@ async function installPackageByUpload({ }); installType = getInstallType({ pkgVersion: packageInfo.version, installedPkg }); + + telemetryEvent.packageName = packageInfo.name; + telemetryEvent.newVersion = packageInfo.version; + telemetryEvent.installType = installType; + telemetryEvent.currentVersion = installedPkg?.attributes.version || 'not_installed'; + if (installType !== 'install') { throw new PackageOperationNotSupportedError( `Package upload only supports fresh installations. Package ${packageInfo.name} is already installed, please uninstall first.` @@ -364,12 +416,24 @@ async function installPackageByUpload({ installSource, }) .then((assets) => { + sendEvent({ + ...telemetryEvent, + status: 'success', + }); return { assets, status: 'installed', installType }; }) .catch(async (err: Error) => { + sendEvent({ + ...telemetryEvent, + errorMessage: err.message, + }); return { error: err, installType }; }); } catch (e) { + sendEvent({ + ...telemetryEvent, + errorMessage: e.message, + }); return { error: e, installType }; } } diff --git a/x-pack/plugins/fleet/server/services/package_policy.test.ts b/x-pack/plugins/fleet/server/services/package_policy.test.ts index dcc00251e70f4..36976bea4a970 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.test.ts @@ -134,7 +134,7 @@ jest.mock('./epm/packages/cleanup', () => { }; }); -jest.mock('./upgrade_usage', () => { +jest.mock('./upgrade_sender', () => { return { sendTelemetryEvents: jest.fn(), }; diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index af5596964740a..20434e8290457 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -67,8 +67,8 @@ import { compileTemplate } from './epm/agent/agent'; import { normalizeKuery } from './saved_object'; import { appContextService } from '.'; import { removeOldAssets } from './epm/packages/cleanup'; -import type { PackagePolicyUpgradeUsage } from './upgrade_usage'; -import { sendTelemetryEvents } from './upgrade_usage'; +import type { PackageUpdateEvent, UpdateEventType } from './upgrade_sender'; +import { sendTelemetryEvents } from './upgrade_sender'; export type InputsOverride = Partial & { vars?: Array; @@ -423,12 +423,13 @@ class PackagePolicyService { }); if (packagePolicy.package.version !== currentVersion) { - const upgradeTelemetry: PackagePolicyUpgradeUsage = { - package_name: packagePolicy.package.name, - current_version: currentVersion || 'unknown', - new_version: packagePolicy.package.version, + const upgradeTelemetry: PackageUpdateEvent = { + packageName: packagePolicy.package.name, + currentVersion: currentVersion || 'unknown', + newVersion: packagePolicy.package.version, status: 'success', dryRun: false, + eventType: 'package-policy-upgrade' as UpdateEventType, }; sendTelemetryEvents( appContextService.getLogger(), @@ -668,13 +669,14 @@ class PackagePolicyService { const hasErrors = 'errors' in updatedPackagePolicy; if (packagePolicy.package.version !== packageInfo.version) { - const upgradeTelemetry: PackagePolicyUpgradeUsage = { - package_name: packageInfo.name, - current_version: packagePolicy.package.version, - new_version: packageInfo.version, + const upgradeTelemetry: PackageUpdateEvent = { + packageName: packageInfo.name, + currentVersion: packagePolicy.package.version, + newVersion: packageInfo.version, status: hasErrors ? 'failure' : 'success', error: hasErrors ? updatedPackagePolicy.errors : undefined, dryRun: true, + eventType: 'package-policy-upgrade' as UpdateEventType, }; sendTelemetryEvents( appContextService.getLogger(), diff --git a/x-pack/plugins/fleet/server/services/upgrade_usage.test.ts b/x-pack/plugins/fleet/server/services/upgrade_sender.test.ts similarity index 73% rename from x-pack/plugins/fleet/server/services/upgrade_usage.test.ts rename to x-pack/plugins/fleet/server/services/upgrade_sender.test.ts index 5445ad233eddc..c8a64a7172b39 100644 --- a/x-pack/plugins/fleet/server/services/upgrade_usage.test.ts +++ b/x-pack/plugins/fleet/server/services/upgrade_sender.test.ts @@ -11,8 +11,8 @@ import { loggingSystemMock } from 'src/core/server/mocks'; import type { TelemetryEventsSender } from '../telemetry/sender'; import { createMockTelemetryEventsSender } from '../telemetry/__mocks__'; -import { sendTelemetryEvents, capErrorSize } from './upgrade_usage'; -import type { PackagePolicyUpgradeUsage } from './upgrade_usage'; +import { sendTelemetryEvents, capErrorSize, UpdateEventType } from './upgrade_sender'; +import type { PackageUpdateEvent } from './upgrade_sender'; describe('sendTelemetryEvents', () => { let eventsTelemetryMock: jest.Mocked; @@ -24,23 +24,24 @@ describe('sendTelemetryEvents', () => { }); it('should queue telemetry events with generic error', () => { - const upgardeMessage: PackagePolicyUpgradeUsage = { - package_name: 'aws', - current_version: '0.6.1', - new_version: '1.3.0', + const upgradeMessage: PackageUpdateEvent = { + packageName: 'aws', + currentVersion: '0.6.1', + newVersion: '1.3.0', status: 'failure', error: [ { key: 'queueUrl', message: ['Queue URL is required'] }, { message: 'Invalid format' }, ], dryRun: true, + eventType: UpdateEventType.PACKAGE_POLICY_UPGRADE, }; - sendTelemetryEvents(loggerMock, eventsTelemetryMock, upgardeMessage); + sendTelemetryEvents(loggerMock, eventsTelemetryMock, upgradeMessage); expect(eventsTelemetryMock.queueTelemetryEvents).toHaveBeenCalledWith('fleet-upgrades', [ { - current_version: '0.6.1', + currentVersion: '0.6.1', error: [ { key: 'queueUrl', @@ -50,11 +51,12 @@ describe('sendTelemetryEvents', () => { message: 'Invalid format', }, ], - error_message: ['Field is required', 'Invalid format'], - new_version: '1.3.0', - package_name: 'aws', + errorMessage: ['Field is required', 'Invalid format'], + newVersion: '1.3.0', + packageName: 'aws', status: 'failure', dryRun: true, + eventType: 'package-policy-upgrade', }, ]); }); diff --git a/x-pack/plugins/fleet/server/services/upgrade_usage.ts b/x-pack/plugins/fleet/server/services/upgrade_sender.ts similarity index 69% rename from x-pack/plugins/fleet/server/services/upgrade_usage.ts rename to x-pack/plugins/fleet/server/services/upgrade_sender.ts index 68bb126496e01..9069ab68b55a3 100644 --- a/x-pack/plugins/fleet/server/services/upgrade_usage.ts +++ b/x-pack/plugins/fleet/server/services/upgrade_sender.ts @@ -8,15 +8,23 @@ import type { Logger } from 'src/core/server'; import type { TelemetryEventsSender } from '../telemetry/sender'; +import type { InstallType } from '../types'; -export interface PackagePolicyUpgradeUsage { - package_name: string; - current_version: string; - new_version: string; +export interface PackageUpdateEvent { + packageName: string; + currentVersion: string; + newVersion: string; status: 'success' | 'failure'; - error?: UpgradeError[]; dryRun?: boolean; - error_message?: string[]; + errorMessage?: string[] | string; + error?: UpgradeError[]; + eventType: UpdateEventType; + installType?: InstallType; +} + +export enum UpdateEventType { + PACKAGE_POLICY_UPGRADE = 'package-policy-upgrade', + PACKAGE_INSTALL = 'package-install', } export interface UpgradeError { @@ -30,19 +38,19 @@ export const FLEET_UPGRADES_CHANNEL_NAME = 'fleet-upgrades'; export function sendTelemetryEvents( logger: Logger, eventsTelemetry: TelemetryEventsSender | undefined, - upgradeUsage: PackagePolicyUpgradeUsage + upgradeEvent: PackageUpdateEvent ) { if (eventsTelemetry === undefined) { return; } try { - const cappedErrors = capErrorSize(upgradeUsage.error || [], MAX_ERROR_SIZE); + const cappedErrors = capErrorSize(upgradeEvent.error || [], MAX_ERROR_SIZE); eventsTelemetry.queueTelemetryEvents(FLEET_UPGRADES_CHANNEL_NAME, [ { - ...upgradeUsage, - error: upgradeUsage.error ? cappedErrors : undefined, - error_message: makeErrorGeneric(cappedErrors), + ...upgradeEvent, + error: upgradeEvent.error ? cappedErrors : undefined, + errorMessage: upgradeEvent.errorMessage || makeErrorGeneric(cappedErrors), }, ]); } catch (exc) { diff --git a/x-pack/plugins/fleet/server/telemetry/sender.test.ts b/x-pack/plugins/fleet/server/telemetry/sender.test.ts index 8fe4c6e150ff9..a1ba0693bf3f3 100644 --- a/x-pack/plugins/fleet/server/telemetry/sender.test.ts +++ b/x-pack/plugins/fleet/server/telemetry/sender.test.ts @@ -15,6 +15,8 @@ import type { InfoResponse } from '@elastic/elasticsearch/lib/api/types'; import { loggingSystemMock } from 'src/core/server/mocks'; +import { UpdateEventType } from '../services/upgrade_sender'; + import { TelemetryEventsSender } from './sender'; jest.mock('axios', () => { @@ -38,7 +40,13 @@ describe('TelemetryEventsSender', () => { describe('queueTelemetryEvents', () => { it('queues two events', () => { sender.queueTelemetryEvents('fleet-upgrades', [ - { package_name: 'system', current_version: '0.3', new_version: '1.0', status: 'success' }, + { + packageName: 'system', + currentVersion: '0.3', + newVersion: '1.0', + status: 'success', + eventType: UpdateEventType.PACKAGE_POLICY_UPGRADE, + }, ]); expect(sender['queuesPerChannel']['fleet-upgrades']).toBeDefined(); }); @@ -54,7 +62,13 @@ describe('TelemetryEventsSender', () => { }; sender.queueTelemetryEvents('fleet-upgrades', [ - { package_name: 'apache', current_version: '0.3', new_version: '1.0', status: 'success' }, + { + packageName: 'apache', + currentVersion: '0.3', + newVersion: '1.0', + status: 'success', + eventType: UpdateEventType.PACKAGE_POLICY_UPGRADE, + }, ]); sender['sendEvents'] = jest.fn(); @@ -74,7 +88,13 @@ describe('TelemetryEventsSender', () => { sender['telemetryStart'] = telemetryStart; sender.queueTelemetryEvents('fleet-upgrades', [ - { package_name: 'system', current_version: '0.3', new_version: '1.0', status: 'success' }, + { + packageName: 'system', + currentVersion: '0.3', + newVersion: '1.0', + status: 'success', + eventType: UpdateEventType.PACKAGE_POLICY_UPGRADE, + }, ]); sender['sendEvents'] = jest.fn(); diff --git a/x-pack/plugins/fleet/server/telemetry/sender.ts b/x-pack/plugins/fleet/server/telemetry/sender.ts index 3bda17fbd1d79..e7413872b6245 100644 --- a/x-pack/plugins/fleet/server/telemetry/sender.ts +++ b/x-pack/plugins/fleet/server/telemetry/sender.ts @@ -138,7 +138,7 @@ export class TelemetryEventsSender { clusterInfo?.version?.number ); } catch (err) { - this.logger.warn(`Error sending telemetry events data: ${err}`); + this.logger.debug(`Error sending telemetry events data: ${err}`); queue.clearEvents(); } } @@ -175,7 +175,7 @@ export class TelemetryEventsSender { }); this.logger.debug(`Events sent!. Response: ${resp.status} ${JSON.stringify(resp.data)}`); } catch (err) { - this.logger.warn( + this.logger.debug( `Error sending events: ${err.response.status} ${JSON.stringify(err.response.data)}` ); } diff --git a/x-pack/plugins/fleet/server/telemetry/types.ts b/x-pack/plugins/fleet/server/telemetry/types.ts index 4351546ecdf02..3b6478d68fba7 100644 --- a/x-pack/plugins/fleet/server/telemetry/types.ts +++ b/x-pack/plugins/fleet/server/telemetry/types.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { PackagePolicyUpgradeUsage } from '../services/upgrade_usage'; +import type { PackageUpdateEvent } from '../services/upgrade_sender'; export interface FleetTelemetryChannelEvents { // channel name => event type - 'fleet-upgrades': PackagePolicyUpgradeUsage; + 'fleet-upgrades': PackageUpdateEvent; } export type FleetTelemetryChannel = keyof FleetTelemetryChannelEvents; From 29981ad79c8261239917502bdc7a15fc12ac0a14 Mon Sep 17 00:00:00 2001 From: Ersin Erdal <92688503+ersin-erdal@users.noreply.github.com> Date: Thu, 11 Nov 2021 10:31:14 +0100 Subject: [PATCH 36/51] [Actionable Observability] Add links to navigate from alerts table to rule (#118035) [Actionable Observability] Add links to navigate from alerts table and flyout to rule generate it --- .../components/app/section/alerts/index.tsx | 9 +- .../observability/public/config/index.ts | 9 ++ .../observability/public/config/paths.ts | 19 ++++ .../public/config/translations.ts | 104 ++++++++++++++++++ .../pages/alerts/alerts_flyout/index.tsx | 53 +++++---- .../pages/alerts/alerts_table_t_grid.tsx | 58 +++++++--- .../public/pages/alerts/translations.ts | 61 ---------- .../services/observability/alerts/common.ts | 17 +++ .../apps/observability/alerts/index.ts | 40 +++---- 9 files changed, 244 insertions(+), 126 deletions(-) create mode 100644 x-pack/plugins/observability/public/config/index.ts create mode 100644 x-pack/plugins/observability/public/config/paths.ts create mode 100644 x-pack/plugins/observability/public/config/translations.ts delete mode 100644 x-pack/plugins/observability/public/pages/alerts/translations.ts diff --git a/x-pack/plugins/observability/public/components/app/section/alerts/index.tsx b/x-pack/plugins/observability/public/components/app/section/alerts/index.tsx index 44f699c6c390b..cf3ac2b6c7be5 100644 --- a/x-pack/plugins/observability/public/components/app/section/alerts/index.tsx +++ b/x-pack/plugins/observability/public/components/app/section/alerts/index.tsx @@ -24,6 +24,7 @@ import { EuiSelect } from '@elastic/eui'; import { uniqBy } from 'lodash'; import { Alert } from '../../../../../../alerting/common'; import { usePluginContext } from '../../../../hooks/use_plugin_context'; +import { paths } from '../../../../config'; const ALL_TYPES = 'ALL_TYPES'; const allTypes = { @@ -41,8 +42,8 @@ export function AlertsSection({ alerts }: Props) { const { config, core } = usePluginContext(); const [filter, setFilter] = useState(ALL_TYPES); const manageLink = config.unsafe.alertingExperience.enabled - ? core.http.basePath.prepend(`/app/observability/alerts`) - : core.http.basePath.prepend(`/app/management/insightsAndAlerting/triggersActions/rules`); + ? core.http.basePath.prepend(paths.observability.alerts) + : core.http.basePath.prepend(paths.management.rules); const filterOptions = uniqBy(alerts, (alert) => alert.consumer).map(({ consumer }) => ({ value: consumer, text: consumer, @@ -89,9 +90,7 @@ export function AlertsSection({ alerts }: Props) { {alert.name} diff --git a/x-pack/plugins/observability/public/config/index.ts b/x-pack/plugins/observability/public/config/index.ts new file mode 100644 index 0000000000000..fc6300acc4716 --- /dev/null +++ b/x-pack/plugins/observability/public/config/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { paths } from './paths'; +export { translations } from './translations'; diff --git a/x-pack/plugins/observability/public/config/paths.ts b/x-pack/plugins/observability/public/config/paths.ts new file mode 100644 index 0000000000000..57bbc95fef40b --- /dev/null +++ b/x-pack/plugins/observability/public/config/paths.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const paths = { + observability: { + alerts: '/app/observability/alerts', + }, + management: { + rules: '/app/management/insightsAndAlerting/triggersActions/rules', + ruleDetails: (ruleId: string) => + `/app/management/insightsAndAlerting/triggersActions/rule/${encodeURI(ruleId)}`, + alertDetails: (alertId: string) => + `/app/management/insightsAndAlerting/triggersActions/alert/${encodeURI(alertId)}`, + }, +}; diff --git a/x-pack/plugins/observability/public/config/translations.ts b/x-pack/plugins/observability/public/config/translations.ts new file mode 100644 index 0000000000000..265787ede4473 --- /dev/null +++ b/x-pack/plugins/observability/public/config/translations.ts @@ -0,0 +1,104 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const translations = { + alertsTable: { + viewDetailsTextLabel: i18n.translate('xpack.observability.alertsTable.viewDetailsTextLabel', { + defaultMessage: 'View details', + }), + viewInAppTextLabel: i18n.translate('xpack.observability.alertsTable.viewInAppTextLabel', { + defaultMessage: 'View in app', + }), + moreActionsTextLabel: i18n.translate('xpack.observability.alertsTable.moreActionsTextLabel', { + defaultMessage: 'More actions', + }), + notEnoughPermissions: i18n.translate('xpack.observability.alertsTable.notEnoughPermissions', { + defaultMessage: 'Additional privileges required', + }), + statusColumnDescription: i18n.translate( + 'xpack.observability.alertsTGrid.statusColumnDescription', + { + defaultMessage: 'Alert Status', + } + ), + lastUpdatedColumnDescription: i18n.translate( + 'xpack.observability.alertsTGrid.lastUpdatedColumnDescription', + { + defaultMessage: 'Last updated', + } + ), + durationColumnDescription: i18n.translate( + 'xpack.observability.alertsTGrid.durationColumnDescription', + { + defaultMessage: 'Duration', + } + ), + reasonColumnDescription: i18n.translate( + 'xpack.observability.alertsTGrid.reasonColumnDescription', + { + defaultMessage: 'Reason', + } + ), + actionsTextLabel: i18n.translate('xpack.observability.alertsTable.actionsTextLabel', { + defaultMessage: 'Actions', + }), + loadingTextLabel: i18n.translate('xpack.observability.alertsTable.loadingTextLabel', { + defaultMessage: 'loading alerts', + }), + footerTextLabel: i18n.translate('xpack.observability.alertsTable.footerTextLabel', { + defaultMessage: 'alerts', + }), + showingAlertsTitle: (totalAlerts: number) => + i18n.translate('xpack.observability.alertsTable.showingAlertsTitle', { + values: { totalAlerts }, + defaultMessage: '{totalAlerts, plural, =1 {alert} other {alerts}}', + }), + viewRuleDetailsButtonText: i18n.translate( + 'xpack.observability.alertsTable.viewRuleDetailsButtonText', + { + defaultMessage: 'View rule details', + } + ), + }, + alertsFlyout: { + statusLabel: i18n.translate('xpack.observability.alertsFlyout.statusLabel', { + defaultMessage: 'Status', + }), + lastUpdatedLabel: i18n.translate('xpack.observability.alertsFlyout.lastUpdatedLabel', { + defaultMessage: 'Last updated', + }), + durationLabel: i18n.translate('xpack.observability.alertsFlyout.durationLabel', { + defaultMessage: 'Duration', + }), + expectedValueLabel: i18n.translate('xpack.observability.alertsFlyout.expectedValueLabel', { + defaultMessage: 'Expected value', + }), + actualValueLabel: i18n.translate('xpack.observability.alertsFlyout.actualValueLabel', { + defaultMessage: 'Actual value', + }), + ruleTypeLabel: i18n.translate('xpack.observability.alertsFlyout.ruleTypeLabel', { + defaultMessage: 'Rule type', + }), + reasonTitle: i18n.translate('xpack.observability.alertsFlyout.reasonTitle', { + defaultMessage: 'Reason', + }), + viewRulesDetailsLinkText: i18n.translate( + 'xpack.observability.alertsFlyout.viewRulesDetailsLinkText', + { + defaultMessage: 'View rule details', + } + ), + documentSummaryTitle: i18n.translate('xpack.observability.alertsFlyout.documentSummaryTitle', { + defaultMessage: 'Document Summary', + }), + viewInAppButtonText: i18n.translate('xpack.observability.alertsFlyout.viewInAppButtonText', { + defaultMessage: 'View in app', + }), + }, +}; diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_flyout/index.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_flyout/index.tsx index 034b7522b9136..41f107437d23b 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts_flyout/index.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts_flyout/index.tsx @@ -15,11 +15,12 @@ import { EuiFlyoutFooter, EuiFlyoutHeader, EuiFlyoutProps, + EuiLink, EuiSpacer, EuiText, EuiTitle, + EuiHorizontalRule, } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import type { ALERT_DURATION as ALERT_DURATION_TYPED, ALERT_EVALUATION_THRESHOLD as ALERT_EVALUATION_THRESHOLD_TYPED, @@ -47,6 +48,7 @@ import type { ObservabilityRuleTypeRegistry } from '../../../rules/create_observ import { parseAlert } from '../parse_alert'; import { AlertStatusIndicator } from '../../../components/shared/alert_status_indicator'; import { ExperimentalBadge } from '../../../components/shared/experimental_badge'; +import { translations, paths } from '../../../config'; type AlertsFlyoutProps = { alert?: TopAlert; @@ -77,6 +79,7 @@ export function AlertsFlyout({ const { services } = useKibana(); const { http } = services; const prepend = http?.basePath.prepend; + const decoratedAlerts = useMemo(() => { const parseObservabilityAlert = parseAlert(observabilityRuleTypeRegistry); return (alerts ?? []).map(parseObservabilityAlert); @@ -90,11 +93,12 @@ export function AlertsFlyout({ return null; } + const ruleId = alertData.fields['kibana.alert.rule.uuid'] ?? null; + const linkToRule = ruleId && prepend ? prepend(paths.management.ruleDetails(ruleId)) : null; + const overviewListItems = [ { - title: i18n.translate('xpack.observability.alertsFlyout.statusLabel', { - defaultMessage: 'Status', - }), + title: translations.alertsFlyout.statusLabel, description: ( {moment(alertData.start).format(dateFormat)} ), }, { - title: i18n.translate('xpack.observability.alertsFlyout.durationLabel', { - defaultMessage: 'Duration', - }), + title: translations.alertsFlyout.durationLabel, description: asDuration(alertData.fields[ALERT_DURATION], { extended: true }), }, { - title: i18n.translate('xpack.observability.alertsFlyout.expectedValueLabel', { - defaultMessage: 'Expected value', - }), + title: translations.alertsFlyout.expectedValueLabel, description: alertData.fields[ALERT_EVALUATION_THRESHOLD] ?? '-', }, { - title: i18n.translate('xpack.observability.alertsFlyout.actualValueLabel', { - defaultMessage: 'Actual value', - }), + title: translations.alertsFlyout.actualValueLabel, description: alertData.fields[ALERT_EVALUATION_VALUE] ?? '-', }, { - title: i18n.translate('xpack.observability.alertsFlyout.ruleTypeLabel', { - defaultMessage: 'Rule type', - }), + title: translations.alertsFlyout.ruleTypeLabel, description: alertData.fields[ALERT_RULE_CATEGORY] ?? '-', }, ]; return ( - +

    {alertData.fields[ALERT_RULE_NAME]}

    - - {alertData.reason}
    + +

    {translations.alertsFlyout.reasonTitle}

    +
    + + {alertData.reason} + {!!linkToRule && ( + + {translations.alertsFlyout.viewRulesDetailsLinkText} + + )} + + +

    {translations.alertsFlyout.documentSummaryTitle}

    +
    + - View in app + {translations.alertsFlyout.viewInAppButtonText}
    diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx index a5b229e92f69d..523d0f19be2be 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx @@ -34,10 +34,12 @@ import { EuiDataGridColumn, EuiFlexGroup, EuiFlexItem, + EuiContextMenuItem, EuiContextMenuPanel, EuiPopover, EuiToolTip, } from '@elastic/eui'; + import styled from 'styled-components'; import React, { Suspense, useMemo, useState, useCallback, useEffect } from 'react'; import usePrevious from 'react-use/lib/usePrevious'; @@ -65,7 +67,7 @@ import { getDefaultCellActions } from './default_cell_actions'; import { LazyAlertsFlyout } from '../..'; import { parseAlert } from './parse_alert'; import { CoreStart } from '../../../../../../src/core/public'; -import { translations } from './translations'; +import { translations, paths } from '../../config'; const ALERT_DURATION: typeof ALERT_DURATION_TYPED = ALERT_DURATION_NON_TYPED; const ALERT_REASON: typeof ALERT_REASON_TYPED = ALERT_REASON_NON_TYPED; @@ -115,25 +117,25 @@ export const columns: Array< > = [ { columnHeaderType: 'not-filtered', - displayAsText: translations.statusColumnDescription, + displayAsText: translations.alertsTable.statusColumnDescription, id: ALERT_STATUS, initialWidth: 110, }, { columnHeaderType: 'not-filtered', - displayAsText: translations.lastUpdatedColumnDescription, + displayAsText: translations.alertsTable.lastUpdatedColumnDescription, id: TIMESTAMP, initialWidth: 230, }, { columnHeaderType: 'not-filtered', - displayAsText: translations.durationColumnDescription, + displayAsText: translations.alertsTable.durationColumnDescription, id: ALERT_DURATION, initialWidth: 116, }, { columnHeaderType: 'not-filtered', - displayAsText: translations.reasonColumnDescription, + displayAsText: translations.alertsTable.reasonColumnDescription, id: ALERT_REASON, linkField: '*', }, @@ -188,6 +190,7 @@ function ObservabilityActions({ const toggleActionsPopover = useCallback((id) => { setActionsPopover((current) => (current ? null : id)); }, []); + const casePermissions = useGetUserCasesPermissions(); const event = useMemo(() => { return { @@ -219,6 +222,9 @@ function ObservabilityActions({ onUpdateFailure: onAlertStatusUpdated, }); + const ruleId = alert.fields['kibana.alert.rule.uuid'] ?? null; + const linkToRule = ruleId ? prepend(paths.management.ruleDetails(ruleId)) : null; + const actionsMenuItems = useMemo(() => { return [ ...(casePermissions?.crud @@ -240,37 +246,56 @@ function ObservabilityActions({ ] : []), ...(alertPermissions.crud ? statusActionItems : []), + ...(!!linkToRule + ? [ + + {translations.alertsTable.viewRuleDetailsButtonText} + , + ] + : []), ]; - }, [afterCaseSelection, casePermissions, timelines, event, statusActionItems, alertPermissions]); + }, [ + afterCaseSelection, + casePermissions, + timelines, + event, + statusActionItems, + alertPermissions, + linkToRule, + ]); const actionsToolTip = actionsMenuItems.length <= 0 - ? translations.notEnoughPermissions - : translations.moreActionsTextLabel; + ? translations.alertsTable.notEnoughPermissions + : translations.alertsTable.moreActionsTextLabel; return ( <> - + setFlyoutAlert(alert)} data-test-subj="openFlyoutButton" - aria-label={translations.viewDetailsTextLabel} + aria-label={translations.alertsTable.viewDetailsTextLabel} /> - + @@ -280,7 +305,6 @@ function ObservabilityActions({ { - return {translations.actionsTextLabel}; + return {translations.alertsTable.actionsTextLabel}; }, rowCellRender: (actionProps: ActionProps) => { return ( @@ -377,8 +401,8 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) { hasAlertsCrudPermissions, indexNames, itemsPerPageOptions: [10, 25, 50], - loadingText: translations.loadingTextLabel, - footerText: translations.footerTextLabel, + loadingText: translations.alertsTable.loadingTextLabel, + footerText: translations.alertsTable.footerTextLabel, query: { query: `${ALERT_WORKFLOW_STATUS}: ${workflowStatus}${kuery !== '' ? ` and ${kuery}` : ''}`, language: 'kuery', @@ -399,7 +423,7 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) { filterStatus: workflowStatus as AlertWorkflowStatus, leadingControlColumns, trailingControlColumns, - unit: (totalAlerts: number) => translations.showingAlertsTitle(totalAlerts), + unit: (totalAlerts: number) => translations.alertsTable.showingAlertsTitle(totalAlerts), }; }, [ casePermissions, diff --git a/x-pack/plugins/observability/public/pages/alerts/translations.ts b/x-pack/plugins/observability/public/pages/alerts/translations.ts deleted file mode 100644 index 4578987e839a0..0000000000000 --- a/x-pack/plugins/observability/public/pages/alerts/translations.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const translations = { - viewDetailsTextLabel: i18n.translate('xpack.observability.alertsTable.viewDetailsTextLabel', { - defaultMessage: 'View details', - }), - viewInAppTextLabel: i18n.translate('xpack.observability.alertsTable.viewInAppTextLabel', { - defaultMessage: 'View in app', - }), - moreActionsTextLabel: i18n.translate('xpack.observability.alertsTable.moreActionsTextLabel', { - defaultMessage: 'More actions', - }), - notEnoughPermissions: i18n.translate('xpack.observability.alertsTable.notEnoughPermissions', { - defaultMessage: 'Additional privileges required', - }), - statusColumnDescription: i18n.translate( - 'xpack.observability.alertsTGrid.statusColumnDescription', - { - defaultMessage: 'Alert Status', - } - ), - lastUpdatedColumnDescription: i18n.translate( - 'xpack.observability.alertsTGrid.lastUpdatedColumnDescription', - { - defaultMessage: 'Last updated', - } - ), - durationColumnDescription: i18n.translate( - 'xpack.observability.alertsTGrid.durationColumnDescription', - { - defaultMessage: 'Duration', - } - ), - reasonColumnDescription: i18n.translate( - 'xpack.observability.alertsTGrid.reasonColumnDescription', - { - defaultMessage: 'Reason', - } - ), - actionsTextLabel: i18n.translate('xpack.observability.alertsTable.actionsTextLabel', { - defaultMessage: 'Actions', - }), - loadingTextLabel: i18n.translate('xpack.observability.alertsTable.loadingTextLabel', { - defaultMessage: 'loading alerts', - }), - footerTextLabel: i18n.translate('xpack.observability.alertsTable.footerTextLabel', { - defaultMessage: 'alerts', - }), - showingAlertsTitle: (totalAlerts: number) => - i18n.translate('xpack.observability.alertsTable.showingAlertsTitle', { - values: { totalAlerts }, - defaultMessage: '{totalAlerts, plural, =1 {alert} other {alerts}}', - }), -}; diff --git a/x-pack/test/functional/services/observability/alerts/common.ts b/x-pack/test/functional/services/observability/alerts/common.ts index 373f7558f8739..dd7d49af4fe5a 100644 --- a/x-pack/test/functional/services/observability/alerts/common.ts +++ b/x-pack/test/functional/services/observability/alerts/common.ts @@ -18,6 +18,9 @@ const DATE_WITH_DATA = { const ALERTS_FLYOUT_SELECTOR = 'alertsFlyout'; const FILTER_FOR_VALUE_BUTTON_SELECTOR = 'filterForValue'; const ALERTS_TABLE_CONTAINER_SELECTOR = 'events-viewer-panel'; +const VIEW_RULE_DETAILS_SELECTOR = 'viewRuleDetails'; +const VIEW_RULE_DETAILS_FLYOUT_SELECTOR = 'viewRuleDetailsFlyout'; + const ACTION_COLUMN_INDEX = 1; type WorkflowStatus = 'open' | 'acknowledged' | 'closed'; @@ -150,6 +153,10 @@ export function ObservabilityAlertsCommonProvider({ return await testSubjects.existOrFail('alertsFlyoutViewInAppButton'); }; + const getAlertsFlyoutViewRuleDetailsLinkOrFail = async () => { + return await testSubjects.existOrFail('viewRuleDetailsFlyout'); + }; + const getAlertsFlyoutDescriptionListTitles = async (): Promise => { const flyout = await getAlertsFlyout(); return await testSubjects.findAllDescendant('alertsFlyoutDescriptionListTitle', flyout); @@ -179,6 +186,13 @@ export function ObservabilityAlertsCommonProvider({ await actionsOverflowButton.click(); }; + const viewRuleDetailsButtonClick = async () => { + return await (await testSubjects.find(VIEW_RULE_DETAILS_SELECTOR)).click(); + }; + const viewRuleDetailsLinkClick = async () => { + return await (await testSubjects.find(VIEW_RULE_DETAILS_FLYOUT_SELECTOR)).click(); + }; + // Workflow status const setWorkflowStatusForRow = async (rowIndex: number, workflowStatus: WorkflowStatus) => { await openActionsMenuForRow(rowIndex); @@ -259,5 +273,8 @@ export function ObservabilityAlertsCommonProvider({ navigateWithoutFilter, getExperimentalDisclaimer, getActionsButtonByIndex, + viewRuleDetailsButtonClick, + viewRuleDetailsLinkClick, + getAlertsFlyoutViewRuleDetailsLinkOrFail, }; } diff --git a/x-pack/test/observability_functional/apps/observability/alerts/index.ts b/x-pack/test/observability_functional/apps/observability/alerts/index.ts index 3190a151cb47b..2b760b65a1c46 100644 --- a/x-pack/test/observability_functional/apps/observability/alerts/index.ts +++ b/x-pack/test/observability_functional/apps/observability/alerts/index.ts @@ -20,8 +20,9 @@ const TOTAL_ALERTS_CELL_COUNT = 198; export default ({ getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); + const find = getService('find'); - describe('Observability alerts', function () { + describe('Observability alerts 1', function () { this.tags('includeFirefox'); const testSubjects = getService('testSubjects'); @@ -178,6 +179,10 @@ export default ({ getService }: FtrProviderContext) => { it('Displays a View in App button', async () => { await observability.alerts.common.getAlertsFlyoutViewInAppButtonOrFail(); }); + + it('Displays a View rule details link', async () => { + await observability.alerts.common.getAlertsFlyoutViewRuleDetailsLinkOrFail(); + }); }); }); @@ -213,28 +218,23 @@ export default ({ getService }: FtrProviderContext) => { }); }); }); - }); - describe('Actions Button', () => { - before(async () => { - await observability.users.setTestUserRole( - observability.users.defineBasicObservabilityRole({ - observabilityCases: ['read'], - logs: ['read'], - }) - ); - await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'); - await observability.alerts.common.navigateToTimeWithData(); - }); + describe('Actions Button', () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'); + await observability.alerts.common.navigateToTimeWithData(); + }); - after(async () => { - await observability.users.restoreDefaultTestUserRole(); - await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'); - }); + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'); + }); - it('Is disabled when a user has only read privilages', async () => { - const actionsButton = await observability.alerts.common.getActionsButtonByIndex(0); - expect(await actionsButton.getAttribute('disabled')).to.be('true'); + it('Opens rule details page when click on "View Rule Details"', async () => { + const actionsButton = await observability.alerts.common.getActionsButtonByIndex(0); + await actionsButton.click(); + await observability.alerts.common.viewRuleDetailsButtonClick(); + expect(await find.existsByCssSelector('[title="Rules and Connectors"]')).to.eql(true); + }); }); }); }); From 16fdfc1b0d5a7fd1de3f22df0553b3fdc14bbf5b Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Thu, 11 Nov 2021 10:20:22 +0000 Subject: [PATCH 37/51] [Stack Monitoring] Update security messaging around alerting (#117505) * Add a getSecurityHealth helper to alerting and update messaging around alerting in Stack Monitoring Co-authored-by: ymao1 --- .../server/lib/get_security_health.test.ts | 84 +++++++++++++++++++ .../server/lib/get_security_health.ts | 38 +++++++++ x-pack/plugins/alerting/server/mocks.ts | 1 + x-pack/plugins/alerting/server/plugin.ts | 12 +++ .../plugins/alerting/server/routes/health.ts | 20 ++--- .../alerting/server/routes/legacy/health.ts | 19 ++--- .../public/alerts/lib/alerts_toast.tsx | 6 +- .../elasticsearch/verify_alerting_security.ts | 49 ----------- x-pack/plugins/monitoring/server/plugin.ts | 1 + .../server/routes/api/v1/alerts/enable.ts | 9 +- x-pack/plugins/monitoring/server/types.ts | 2 + 11 files changed, 160 insertions(+), 81 deletions(-) create mode 100644 x-pack/plugins/alerting/server/lib/get_security_health.test.ts create mode 100644 x-pack/plugins/alerting/server/lib/get_security_health.ts delete mode 100644 x-pack/plugins/monitoring/server/lib/elasticsearch/verify_alerting_security.ts diff --git a/x-pack/plugins/alerting/server/lib/get_security_health.test.ts b/x-pack/plugins/alerting/server/lib/get_security_health.test.ts new file mode 100644 index 0000000000000..1253e0c3379b5 --- /dev/null +++ b/x-pack/plugins/alerting/server/lib/get_security_health.test.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getSecurityHealth } from './get_security_health'; + +const createDependencies = ( + isSecurityEnabled: boolean | null, + canEncrypt: boolean, + apiKeysEnabled: boolean +) => { + const isEsSecurityEnabled = async () => isSecurityEnabled; + const isAbleToEncrypt = async () => canEncrypt; + const areApikeysEnabled = async () => apiKeysEnabled; + + const deps: [() => Promise, () => Promise, () => Promise] = [ + isEsSecurityEnabled, + isAbleToEncrypt, + areApikeysEnabled, + ]; + + return deps; +}; + +describe('Get security health', () => { + describe('Correctly returns the overall security health', () => { + test('When ES security enabled status cannot be determined', async () => { + const deps = createDependencies(null, true, true); + const securityHealth = await getSecurityHealth(...deps); + expect(securityHealth).toEqual({ + isSufficientlySecure: false, + hasPermanentEncryptionKey: true, + }); + }); + + test('When ES security is disabled', async () => { + const deps = createDependencies(false, true, true); + const securityHealth = await getSecurityHealth(...deps); + expect(securityHealth).toEqual({ + isSufficientlySecure: true, + hasPermanentEncryptionKey: true, + }); + }); + + test('When ES security is enabled, and API keys are disabled', async () => { + const deps = createDependencies(true, true, false); + const securityHealth = await getSecurityHealth(...deps); + expect(securityHealth).toEqual({ + isSufficientlySecure: false, + hasPermanentEncryptionKey: true, + }); + }); + + test('When ES security is enabled, and API keys are enabled', async () => { + const deps = createDependencies(true, true, true); + const securityHealth = await getSecurityHealth(...deps); + expect(securityHealth).toEqual({ + isSufficientlySecure: true, + hasPermanentEncryptionKey: true, + }); + }); + + test('With encryption enabled', async () => { + const deps = createDependencies(true, true, true); + const securityHealth = await getSecurityHealth(...deps); + expect(securityHealth).toEqual({ + isSufficientlySecure: true, + hasPermanentEncryptionKey: true, + }); + }); + + test('With encryption disabled', async () => { + const deps = createDependencies(true, false, true); + const securityHealth = await getSecurityHealth(...deps); + expect(securityHealth).toEqual({ + isSufficientlySecure: true, + hasPermanentEncryptionKey: false, + }); + }); + }); +}); diff --git a/x-pack/plugins/alerting/server/lib/get_security_health.ts b/x-pack/plugins/alerting/server/lib/get_security_health.ts new file mode 100644 index 0000000000000..1a2097221433b --- /dev/null +++ b/x-pack/plugins/alerting/server/lib/get_security_health.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface SecurityHealth { + isSufficientlySecure: boolean; + hasPermanentEncryptionKey: boolean; +} + +export const getSecurityHealth = async ( + isEsSecurityEnabled: () => Promise, + isAbleToEncrypt: () => Promise, + areApiKeysEnabled: () => Promise +) => { + const esSecurityIsEnabled = await isEsSecurityEnabled(); + const apiKeysAreEnabled = await areApiKeysEnabled(); + const ableToEncrypt = await isAbleToEncrypt(); + + let isSufficientlySecure: boolean; + + if (esSecurityIsEnabled === null) { + isSufficientlySecure = false; + } else { + // if esSecurityIsEnabled = true, then areApiKeysEnabled must be true to enable alerting + // if esSecurityIsEnabled = false, then it does not matter what areApiKeysEnabled is + isSufficientlySecure = !esSecurityIsEnabled || (esSecurityIsEnabled && apiKeysAreEnabled); + } + + const securityHealth: SecurityHealth = { + isSufficientlySecure, + hasPermanentEncryptionKey: ableToEncrypt, + }; + + return securityHealth; +}; diff --git a/x-pack/plugins/alerting/server/mocks.ts b/x-pack/plugins/alerting/server/mocks.ts index 639ba166e00a8..7fb748a305037 100644 --- a/x-pack/plugins/alerting/server/mocks.ts +++ b/x-pack/plugins/alerting/server/mocks.ts @@ -19,6 +19,7 @@ export { rulesClientMock }; const createSetupMock = () => { const mock: jest.Mocked = { registerType: jest.fn(), + getSecurityHealth: jest.fn(), }; return mock; }; diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index f0703defbca3d..982d8907d9b9d 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -65,6 +65,7 @@ import { AlertsConfig } from './config'; import { getHealth } from './health/get_health'; import { AlertingAuthorizationClientFactory } from './alerting_authorization_client_factory'; import { AlertingAuthorization } from './authorization'; +import { getSecurityHealth, SecurityHealth } from './lib/get_security_health'; export const EVENT_LOG_PROVIDER = 'alerting'; export const EVENT_LOG_ACTIONS = { @@ -99,6 +100,7 @@ export interface PluginSetupContract { RecoveryActionGroupId > ): void; + getSecurityHealth: () => Promise; } export interface PluginStartContract { @@ -315,6 +317,16 @@ export class AlertingPlugin { ruleTypeRegistry.register(alertType); } }, + getSecurityHealth: async () => { + return await getSecurityHealth( + async () => (this.licenseState ? this.licenseState.getIsSecurityEnabled() : null), + async () => plugins.encryptedSavedObjects.canEncrypt, + async () => { + const [, { security }] = await core.getStartServices(); + return security?.authc.apiKeys.areAPIKeysEnabled() ?? false; + } + ); + }, }; } diff --git a/x-pack/plugins/alerting/server/routes/health.ts b/x-pack/plugins/alerting/server/routes/health.ts index fa09213dada3a..4f3ed2b542611 100644 --- a/x-pack/plugins/alerting/server/routes/health.ts +++ b/x-pack/plugins/alerting/server/routes/health.ts @@ -14,6 +14,7 @@ import { BASE_ALERTING_API_PATH, AlertingFrameworkHealth, } from '../types'; +import { getSecurityHealth } from '../lib/get_security_health'; const rewriteBodyRes: RewriteResponseCase = ({ isSufficientlySecure, @@ -44,23 +45,16 @@ export const healthRoute = ( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { try { - const isEsSecurityEnabled: boolean | null = licenseState.getIsSecurityEnabled(); - const areApiKeysEnabled = await context.alerting.areApiKeysEnabled(); const alertingFrameworkHeath = await context.alerting.getFrameworkHealth(); - let isSufficientlySecure; - if (isEsSecurityEnabled === null) { - isSufficientlySecure = false; - } else { - // if isEsSecurityEnabled = true, then areApiKeysEnabled must be true to enable alerting - // if isEsSecurityEnabled = false, then it does not matter what areApiKeysEnabled is - isSufficientlySecure = - !isEsSecurityEnabled || (isEsSecurityEnabled && areApiKeysEnabled); - } + const securityHealth = await getSecurityHealth( + async () => (licenseState ? licenseState.getIsSecurityEnabled() : null), + async () => encryptedSavedObjects.canEncrypt, + context.alerting.areApiKeysEnabled + ); const frameworkHealth: AlertingFrameworkHealth = { - isSufficientlySecure, - hasPermanentEncryptionKey: encryptedSavedObjects.canEncrypt, + ...securityHealth, alertingFrameworkHeath, }; diff --git a/x-pack/plugins/alerting/server/routes/legacy/health.ts b/x-pack/plugins/alerting/server/routes/legacy/health.ts index 8c654f103ea86..abea724b63c6f 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/health.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/health.ts @@ -12,6 +12,7 @@ import { verifyApiAccess } from '../../lib/license_api_access'; import { AlertingFrameworkHealth } from '../../types'; import { EncryptedSavedObjectsPluginSetup } from '../../../../encrypted_saved_objects/server'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { getSecurityHealth } from '../../lib/get_security_health'; export function healthRoute( router: AlertingRouter, @@ -31,22 +32,16 @@ export function healthRoute( } trackLegacyRouteUsage('health', usageCounter); try { - const isEsSecurityEnabled: boolean | null = licenseState.getIsSecurityEnabled(); const alertingFrameworkHeath = await context.alerting.getFrameworkHealth(); - const areApiKeysEnabled = await context.alerting.areApiKeysEnabled(); - let isSufficientlySecure; - if (isEsSecurityEnabled === null) { - isSufficientlySecure = false; - } else { - // if isEsSecurityEnabled = true, then areApiKeysEnabled must be true to enable alerting - // if isEsSecurityEnabled = false, then it does not matter what areApiKeysEnabled is - isSufficientlySecure = !isEsSecurityEnabled || (isEsSecurityEnabled && areApiKeysEnabled); - } + const securityHealth = await getSecurityHealth( + async () => (licenseState ? licenseState.getIsSecurityEnabled() : null), + async () => encryptedSavedObjects.canEncrypt, + context.alerting.areApiKeysEnabled + ); const frameworkHealth: AlertingFrameworkHealth = { - isSufficientlySecure, - hasPermanentEncryptionKey: encryptedSavedObjects.canEncrypt, + ...securityHealth, alertingFrameworkHeath, }; diff --git a/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx b/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx index d752ec154089b..10c8f7155134b 100644 --- a/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx +++ b/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx @@ -18,7 +18,7 @@ export interface EnableAlertResponse { disabledWatcherClusterAlerts?: boolean; } -const showTlsAndEncryptionError = () => { +const showApiKeyAndEncryptionError = () => { const settingsUrl = Legacy.shims.docLinks.links.alerting.generalSettings; Legacy.shims.toastNotifications.addWarning({ @@ -32,7 +32,7 @@ const showTlsAndEncryptionError = () => {

    {i18n.translate('xpack.monitoring.healthCheck.tlsAndEncryptionError', { - defaultMessage: `Stack monitoring alerts require Transport Layer Security between Kibana and Elasticsearch, and an encryption key in your kibana.yml file.`, + defaultMessage: `Stack Monitoring rules require API keys to be enabled and an encryption key to be configured.`, })}

    @@ -97,7 +97,7 @@ export const showAlertsToast = (response: EnableAlertResponse) => { response; if (isSufficientlySecure === false || hasPermanentEncryptionKey === false) { - showTlsAndEncryptionError(); + showApiKeyAndEncryptionError(); } else if (disabledWatcherClusterAlerts === false) { showUnableToDisableWatcherClusterAlertsError(); } else if (disabledWatcherClusterAlerts === true) { diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/verify_alerting_security.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/verify_alerting_security.ts deleted file mode 100644 index f5f9c80e0e4d3..0000000000000 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/verify_alerting_security.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { RequestHandlerContext } from 'kibana/server'; -import { EncryptedSavedObjectsPluginSetup } from '../../../../encrypted_saved_objects/server'; - -export interface AlertingFrameworkHealth { - isSufficientlySecure: boolean; - hasPermanentEncryptionKey: boolean; -} - -export interface XPackUsageSecurity { - security?: { - enabled?: boolean; - ssl?: { - http?: { - enabled?: boolean; - }; - }; - }; -} - -export class AlertingSecurity { - public static readonly getSecurityHealth = async ( - context: RequestHandlerContext, - encryptedSavedObjects?: EncryptedSavedObjectsPluginSetup - ): Promise => { - const { - security: { - enabled: isSecurityEnabled = false, - ssl: { http: { enabled: isTLSEnabled = false } = {} } = {}, - } = {}, - } = ( - await context.core.elasticsearch.client.asInternalUser.transport.request({ - method: 'GET', - path: '/_xpack/usage', - }) - ).body as XPackUsageSecurity; - - return { - isSufficientlySecure: !isSecurityEnabled || (isSecurityEnabled && isTLSEnabled), - hasPermanentEncryptionKey: encryptedSavedObjects?.canEncrypt === true, - }; - }; -} diff --git a/x-pack/plugins/monitoring/server/plugin.ts b/x-pack/plugins/monitoring/server/plugin.ts index 557a9b5e2a3d2..ff07ea0f4a26d 100644 --- a/x-pack/plugins/monitoring/server/plugin.ts +++ b/x-pack/plugins/monitoring/server/plugin.ts @@ -202,6 +202,7 @@ export class MonitoringPlugin router, licenseService: this.licenseService, encryptedSavedObjects: plugins.encryptedSavedObjects, + alerting: plugins.alerting, logger: this.log, }); initInfraSource(config, plugins.infra); diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts index 6724819c30d56..7185d399b3534 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts @@ -11,7 +11,6 @@ import { AlertsFactory } from '../../../../alerts'; import { LegacyServer, RouteDependencies } from '../../../../types'; import { ALERT_ACTION_TYPE_LOG } from '../../../../../common/constants'; import { ActionResult } from '../../../../../../actions/common'; -import { AlertingSecurity } from '../../../../lib/elasticsearch/verify_alerting_security'; import { disableWatcherClusterAlerts } from '../../../../lib/alerts/disable_watcher_cluster_alerts'; import { AlertTypeParams, SanitizedAlert } from '../../../../../../alerting/common'; @@ -38,12 +37,14 @@ export function enableAlertsRoute(server: LegacyServer, npRoute: RouteDependenci const alerts = AlertsFactory.getAll(); if (alerts.length) { - const { isSufficientlySecure, hasPermanentEncryptionKey } = - await AlertingSecurity.getSecurityHealth(context, npRoute.encryptedSavedObjects); + const { isSufficientlySecure, hasPermanentEncryptionKey } = npRoute.alerting + ?.getSecurityHealth + ? await npRoute.alerting?.getSecurityHealth() + : { isSufficientlySecure: false, hasPermanentEncryptionKey: false }; if (!isSufficientlySecure || !hasPermanentEncryptionKey) { server.log.info( - `Skipping alert creation for "${context.infra.spaceId}" space; Stack monitoring alerts require Transport Layer Security between Kibana and Elasticsearch, and an encryption key in your kibana.yml file.` + `Skipping rule creation for "${context.infra.spaceId}" space; Stack Monitoring rules require API keys to be enabled and an encryption key to be configured.` ); return response.ok({ body: { diff --git a/x-pack/plugins/monitoring/server/types.ts b/x-pack/plugins/monitoring/server/types.ts index 14071aafaea12..14023ccce41ae 100644 --- a/x-pack/plugins/monitoring/server/types.ts +++ b/x-pack/plugins/monitoring/server/types.ts @@ -28,6 +28,7 @@ import { PluginSetupContract as AlertingPluginSetupContract, } from '../../alerting/server'; import { InfraPluginSetup, InfraRequestHandlerContext } from '../../infra/server'; +import { PluginSetupContract as AlertingPluginSetup } from '../../alerting/server'; import { LicensingPluginStart } from '../../licensing/server'; import { PluginSetupContract as FeaturesPluginSetupContract } from '../../features/server'; import { EncryptedSavedObjectsPluginSetup } from '../../encrypted_saved_objects/server'; @@ -80,6 +81,7 @@ export interface RouteDependencies { router: IRouter; licenseService: MonitoringLicenseService; encryptedSavedObjects?: EncryptedSavedObjectsPluginSetup; + alerting?: AlertingPluginSetup; logger: Logger; } From ed7faa8524e88cf8d683f0b51cf89ce491907212 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 11 Nov 2021 11:51:15 +0100 Subject: [PATCH 38/51] Update app services code owners (#118194) * Be regular code-owner for previously CC directories * Remove /x-pack/plugins/drilldowns as there is no such path anymore * Add /examples/search_examples/ as CO * Remove any duplicates --- .github/CODEOWNERS | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d532d4b681c77..370f377d74c89 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -59,6 +59,7 @@ /examples/url_generators_explorer/ @elastic/kibana-app-services /examples/field_formats_example/ @elastic/kibana-app-services /examples/partial_results_example/ @elastic/kibana-app-services +/examples/search_examples/ @elastic/kibana-app-services /packages/elastic-datemath/ @elastic/kibana-app-services /packages/kbn-interpreter/ @elastic/kibana-app-services /packages/kbn-react-field/ @elastic/kibana-app-services @@ -78,18 +79,15 @@ /src/plugins/ui_actions/ @elastic/kibana-app-services /src/plugins/index_pattern_field_editor @elastic/kibana-app-services /src/plugins/screenshot_mode @elastic/kibana-app-services +/src/plugins/bfetch/ @elastic/kibana-app-services +/src/plugins/index_pattern_management/ @elastic/kibana-app-services +/src/plugins/inspector/ @elastic/kibana-app-services /x-pack/examples/ui_actions_enhanced_examples/ @elastic/kibana-app-services /x-pack/plugins/data_enhanced/ @elastic/kibana-app-services /x-pack/plugins/embeddable_enhanced/ @elastic/kibana-app-services /x-pack/plugins/ui_actions_enhanced/ @elastic/kibana-app-services /x-pack/plugins/runtime_fields @elastic/kibana-app-services /x-pack/test/search_sessions_integration/ @elastic/kibana-app-services -#CC# /src/plugins/bfetch/ @elastic/kibana-app-services -#CC# /src/plugins/index_pattern_management/ @elastic/kibana-app-services -#CC# /src/plugins/inspector/ @elastic/kibana-app-services -#CC# /src/plugins/share/ @elastic/kibana-app-services -#CC# /x-pack/plugins/drilldowns/ @elastic/kibana-app-services -#CC# /packages/kbn-interpreter/ @elastic/kibana-app-services ### Observability Plugins From 06255cea1eed8c5b2fe42b01131ae6862499df3b Mon Sep 17 00:00:00 2001 From: Kerry Gallagher Date: Thu, 11 Nov 2021 10:58:04 +0000 Subject: [PATCH 39/51] Mark index as hidden within index template (#117839) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/rule_data_plugin_service/resource_installer.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts index 3798506eeacd1..bfdec28a50987 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts @@ -309,6 +309,7 @@ export class ResourceInstaller { template: { settings: { + hidden: true, 'index.lifecycle': { name: ilmPolicyName, // TODO: fix the types in the ES package, they don't include rollover_alias??? From c0cb59b697e62c73e38eb3b1bfdc61191d47ef11 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Thu, 11 Nov 2021 11:04:24 +0000 Subject: [PATCH 40/51] Change Import Rules Modal Description (#118216) --- .../detections/pages/detection_engine/rules/translations.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts index 15ff91cac5096..ca1b1f57b8399 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts @@ -551,7 +551,8 @@ export const IMPORT_RULE_BTN_TITLE = i18n.translate( export const SELECT_RULE = i18n.translate( 'xpack.securitySolution.detectionEngine.components.importRuleModal.selectRuleDescription', { - defaultMessage: 'Select Security rules (as exported from the Detection Rules page) to import', + defaultMessage: + 'Select rules and actions (as exported from the Security > Rules page) to import', } ); From 7c16e2e57ff7365b587d7d0b7103ed7f6512a8a4 Mon Sep 17 00:00:00 2001 From: Mikhail Shustov Date: Thu, 11 Nov 2021 12:13:23 +0100 Subject: [PATCH 41/51] Include tracing information in the Kibana logs (#112973) * change APM nodejs agent default By default APM agent instruments the code to be a base for log correlation. But it doesn't send transactions to the APM server. * emit trace IDs into the logs * use ELASTIC_APM_DISABLE_SEND to keep APM agent active but disable send when necessary * send data whenver active is set to "true" * update tests * keep APM agent active. control disableSend instead * update snapshot tests * add debug logging * REMOVE me. log path to the agent * init APM agent explicitly in test plugin. it uses another package instance * REMOVE me. create transaction explicitly * increase timeout setting for the test * refactor tests * remove debug logs * remove explicit transaction creation * Revert "remove explicit transaction creation" This reverts commit cdf2d308e0af9b8cead3d9b8f6949cfe79584f5d. * point to apm nodejs agent commit temporary until a new version is released * migrate from disableSend to contextPropagationOnly * TO DISCUSS. what if we enforce contextPropagationOnly to be configured when active is defined * Revert "TO DISCUSS. what if we enforce contextPropagationOnly to be configured when active is defined" This reverts commit 62dda4fb27f89081a7408d0c5d2bd7e022d34cc1. * bump to version with fix * commit using @elastic.co Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .buildkite/scripts/common/env.sh | 5 +- package.json | 2 +- .../kbn-apm-config-loader/src/config.test.ts | 139 +++++++++++++++++- packages/kbn-apm-config-loader/src/config.ts | 39 ++++- packages/kbn-logging/src/log_record.ts | 3 + .../__snapshots__/logging_system.test.ts.snap | 6 + .../__snapshots__/json_layout.test.ts.snap | 23 +++ .../logging/layouts/json_layout.test.ts | 47 ++++++ .../server/logging/layouts/json_layout.ts | 3 + src/core/server/logging/logger.ts | 12 +- vars/kibanaPipeline.groovy | 5 +- .../functional_execution_context/config.ts | 1 + .../alerts/server/ensure_apm_started.ts | 13 ++ .../fixtures/plugins/alerts/server/index.ts | 1 + .../fixtures/plugins/alerts/server/plugin.ts | 27 ++++ .../tests/index.ts | 1 + .../tests/log_correlation.ts | 38 +++++ x-pack/test/performance/config.ts | 1 + yarn.lock | 18 +-- 19 files changed, 360 insertions(+), 24 deletions(-) create mode 100644 x-pack/test/functional_execution_context/fixtures/plugins/alerts/server/ensure_apm_started.ts create mode 100644 x-pack/test/functional_execution_context/tests/log_correlation.ts diff --git a/.buildkite/scripts/common/env.sh b/.buildkite/scripts/common/env.sh index 0715b07fd58e8..b5acfe140df24 100755 --- a/.buildkite/scripts/common/env.sh +++ b/.buildkite/scripts/common/env.sh @@ -38,8 +38,10 @@ export ELASTIC_APM_TRANSACTION_SAMPLE_RATE=0.1 if is_pr; then if [[ "${GITHUB_PR_LABELS:-}" == *"ci:collect-apm"* ]]; then export ELASTIC_APM_ACTIVE=true + export ELASTIC_APM_CONTEXT_PROPAGATION_ONLY=false else - export ELASTIC_APM_ACTIVE=false + export ELASTIC_APM_ACTIVE=true + export ELASTIC_APM_CONTEXT_PROPAGATION_ONLY=true fi if [[ "${GITHUB_STEP_COMMIT_STATUS_ENABLED:-}" != "true" ]]; then @@ -61,6 +63,7 @@ if is_pr; then export PR_TARGET_BRANCH="$GITHUB_PR_TARGET_BRANCH" else export ELASTIC_APM_ACTIVE=true + export ELASTIC_APM_CONTEXT_PROPAGATION_ONLY=false export CHECKS_REPORTER_ACTIVE=false fi diff --git a/package.json b/package.json index 39bfc891e65b3..5eba8a9265d70 100644 --- a/package.json +++ b/package.json @@ -223,7 +223,7 @@ "deep-freeze-strict": "^1.1.1", "deepmerge": "^4.2.2", "del": "^5.1.0", - "elastic-apm-node": "^3.23.0", + "elastic-apm-node": "3.24.0", "execa": "^4.0.2", "exit-hook": "^2.2.0", "expiry-js": "0.1.7", diff --git a/packages/kbn-apm-config-loader/src/config.test.ts b/packages/kbn-apm-config-loader/src/config.test.ts index 60d773e3a420b..b0beebfefd6bd 100644 --- a/packages/kbn-apm-config-loader/src/config.test.ts +++ b/packages/kbn-apm-config-loader/src/config.test.ts @@ -21,7 +21,7 @@ describe('ApmConfiguration', () => { beforeEach(() => { // start with an empty env to avoid CI from spoiling snapshots, env is unique for each jest file process.env = {}; - + devConfigMock.raw = {}; packageMock.raw = { version: '8.0.0', build: { @@ -86,10 +86,11 @@ describe('ApmConfiguration', () => { let config = new ApmConfiguration(mockedRootDir, {}, false); expect(config.getConfig('serviceName')).toMatchInlineSnapshot(` Object { - "active": false, + "active": true, "breakdownMetrics": true, "captureSpanStackTraces": false, "centralConfig": false, + "contextPropagationOnly": true, "environment": "development", "globalLabels": Object {}, "logUncaughtExceptions": true, @@ -105,12 +106,13 @@ describe('ApmConfiguration', () => { config = new ApmConfiguration(mockedRootDir, {}, true); expect(config.getConfig('serviceName')).toMatchInlineSnapshot(` Object { - "active": false, + "active": true, "breakdownMetrics": false, "captureBody": "off", "captureHeaders": false, "captureSpanStackTraces": false, "centralConfig": false, + "contextPropagationOnly": true, "environment": "development", "globalLabels": Object { "git_rev": "sha", @@ -162,13 +164,12 @@ describe('ApmConfiguration', () => { it('does not load the configuration from the dev config in distributable', () => { devConfigMock.raw = { - active: true, - serverUrl: 'https://dev-url.co', + active: false, }; const config = new ApmConfiguration(mockedRootDir, {}, true); expect(config.getConfig('serviceName')).toEqual( expect.objectContaining({ - active: false, + active: true, }) ); }); @@ -224,4 +225,130 @@ describe('ApmConfiguration', () => { }) ); }); + + describe('contextPropagationOnly', () => { + it('sets "active: true" and "contextPropagationOnly: true" by default', () => { + expect(new ApmConfiguration(mockedRootDir, {}, false).getConfig('serviceName')).toEqual( + expect.objectContaining({ + active: true, + contextPropagationOnly: true, + }) + ); + + expect(new ApmConfiguration(mockedRootDir, {}, true).getConfig('serviceName')).toEqual( + expect.objectContaining({ + active: true, + contextPropagationOnly: true, + }) + ); + }); + + it('value from config overrides the default', () => { + const kibanaConfig = { + elastic: { + apm: { + active: false, + contextPropagationOnly: false, + }, + }, + }; + + expect( + new ApmConfiguration(mockedRootDir, kibanaConfig, false).getConfig('serviceName') + ).toEqual( + expect.objectContaining({ + active: false, + contextPropagationOnly: false, + }) + ); + + expect( + new ApmConfiguration(mockedRootDir, kibanaConfig, true).getConfig('serviceName') + ).toEqual( + expect.objectContaining({ + active: false, + contextPropagationOnly: false, + }) + ); + }); + + it('is "false" if "active: true" configured and "contextPropagationOnly" is not specified', () => { + const kibanaConfig = { + elastic: { + apm: { + active: true, + }, + }, + }; + + expect( + new ApmConfiguration(mockedRootDir, kibanaConfig, false).getConfig('serviceName') + ).toEqual( + expect.objectContaining({ + active: true, + contextPropagationOnly: false, + }) + ); + + expect( + new ApmConfiguration(mockedRootDir, kibanaConfig, true).getConfig('serviceName') + ).toEqual( + expect.objectContaining({ + active: true, + contextPropagationOnly: false, + }) + ); + }); + + it('throws if "active: false" set without configuring "contextPropagationOnly: false"', () => { + const kibanaConfig = { + elastic: { + apm: { + active: false, + }, + }, + }; + + expect(() => + new ApmConfiguration(mockedRootDir, kibanaConfig, false).getConfig('serviceName') + ).toThrowErrorMatchingInlineSnapshot( + `"APM is disabled, but context propagation is enabled. Please disable context propagation with contextPropagationOnly:false"` + ); + + expect(() => + new ApmConfiguration(mockedRootDir, kibanaConfig, true).getConfig('serviceName') + ).toThrowErrorMatchingInlineSnapshot( + `"APM is disabled, but context propagation is enabled. Please disable context propagation with contextPropagationOnly:false"` + ); + }); + + it('does not throw if "active: false" and "contextPropagationOnly: false" configured', () => { + const kibanaConfig = { + elastic: { + apm: { + active: false, + contextPropagationOnly: false, + }, + }, + }; + + expect( + new ApmConfiguration(mockedRootDir, kibanaConfig, false).getConfig('serviceName') + ).toEqual( + expect.objectContaining({ + active: false, + contextPropagationOnly: false, + }) + ); + + expect( + new ApmConfiguration(mockedRootDir, kibanaConfig, true).getConfig('serviceName') + ).toEqual( + expect.objectContaining({ + active: false, + contextPropagationOnly: false, + }) + ); + }); + }); }); diff --git a/packages/kbn-apm-config-loader/src/config.ts b/packages/kbn-apm-config-loader/src/config.ts index 999e4ce3a6805..ecafcbd7e3261 100644 --- a/packages/kbn-apm-config-loader/src/config.ts +++ b/packages/kbn-apm-config-loader/src/config.ts @@ -16,7 +16,8 @@ import type { AgentConfigOptions } from 'elastic-apm-node'; // https://www.elastic.co/guide/en/apm/agent/nodejs/current/configuration.html const DEFAULT_CONFIG: AgentConfigOptions = { - active: false, + active: true, + contextPropagationOnly: true, environment: 'development', logUncaughtExceptions: true, globalLabels: {}, @@ -71,6 +72,8 @@ export class ApmConfiguration { private getBaseConfig() { if (!this.baseConfig) { + const configFromSources = this.getConfigFromAllSources(); + this.baseConfig = merge( { serviceVersion: this.kibanaVersion, @@ -79,9 +82,7 @@ export class ApmConfiguration { this.getUuidConfig(), this.getGitConfig(), this.getCiConfig(), - this.getConfigFromKibanaConfig(), - this.getDevConfig(), - this.getConfigFromEnv() + configFromSources ); /** @@ -114,6 +115,12 @@ export class ApmConfiguration { config.active = true; } + if (process.env.ELASTIC_APM_CONTEXT_PROPAGATION_ONLY === 'true') { + config.contextPropagationOnly = true; + } else if (process.env.ELASTIC_APM_CONTEXT_PROPAGATION_ONLY === 'false') { + config.contextPropagationOnly = false; + } + if (process.env.ELASTIC_APM_ENVIRONMENT || process.env.NODE_ENV) { config.environment = process.env.ELASTIC_APM_ENVIRONMENT || process.env.NODE_ENV; } @@ -249,4 +256,28 @@ export class ApmConfiguration { return {}; } } + + /** + * Reads APM configuration from different sources and merges them together. + */ + private getConfigFromAllSources(): AgentConfigOptions { + const config = merge( + {}, + this.getConfigFromKibanaConfig(), + this.getDevConfig(), + this.getConfigFromEnv() + ); + + if (config.active === false && config.contextPropagationOnly !== false) { + throw new Error( + 'APM is disabled, but context propagation is enabled. Please disable context propagation with contextPropagationOnly:false' + ); + } + + if (config.active === true) { + config.contextPropagationOnly = config.contextPropagationOnly ?? false; + } + + return config; + } } diff --git a/packages/kbn-logging/src/log_record.ts b/packages/kbn-logging/src/log_record.ts index 22931a67a823d..ee9ed0d69b749 100644 --- a/packages/kbn-logging/src/log_record.ts +++ b/packages/kbn-logging/src/log_record.ts @@ -20,4 +20,7 @@ export interface LogRecord { error?: Error; meta?: { [name: string]: any }; pid: number; + spanId?: string; + traceId?: string; + transactionId?: string; } diff --git a/src/core/server/logging/__snapshots__/logging_system.test.ts.snap b/src/core/server/logging/__snapshots__/logging_system.test.ts.snap index 49035cdda3915..e369d7b0cba37 100644 --- a/src/core/server/logging/__snapshots__/logging_system.test.ts.snap +++ b/src/core/server/logging/__snapshots__/logging_system.test.ts.snap @@ -117,7 +117,10 @@ Object { "message": "trace message", "meta": undefined, "pid": Any, + "spanId": undefined, "timestamp": 2012-02-01T14:33:22.011Z, + "traceId": undefined, + "transactionId": undefined, } `; @@ -133,6 +136,9 @@ Object { "some": "value", }, "pid": Any, + "spanId": undefined, "timestamp": 2012-02-01T14:33:22.011Z, + "traceId": undefined, + "transactionId": undefined, } `; diff --git a/src/core/server/logging/layouts/__snapshots__/json_layout.test.ts.snap b/src/core/server/logging/layouts/__snapshots__/json_layout.test.ts.snap index 48bbb19447411..0809dbffce670 100644 --- a/src/core/server/logging/layouts/__snapshots__/json_layout.test.ts.snap +++ b/src/core/server/logging/layouts/__snapshots__/json_layout.test.ts.snap @@ -88,3 +88,26 @@ Object { }, } `; + +exports[`\`format()\` correctly formats record and includes correct ECS version. 7`] = ` +Object { + "@timestamp": "2012-02-01T09:30:22.011-05:00", + "log": Object { + "level": "TRACE", + "logger": "context-7", + }, + "message": "message-6", + "process": Object { + "pid": 5355, + }, + "span": Object { + "id": "spanId-1", + }, + "trace": Object { + "id": "traceId-1", + }, + "transaction": Object { + "id": "transactionId-1", + }, +} +`; diff --git a/src/core/server/logging/layouts/json_layout.test.ts b/src/core/server/logging/layouts/json_layout.test.ts index 56184ebd67aee..84546f777ed0b 100644 --- a/src/core/server/logging/layouts/json_layout.test.ts +++ b/src/core/server/logging/layouts/json_layout.test.ts @@ -58,6 +58,16 @@ const records: LogRecord[] = [ timestamp, pid: 5355, }, + { + context: 'context-7', + level: LogLevel.Trace, + message: 'message-6', + timestamp, + pid: 5355, + spanId: 'spanId-1', + traceId: 'traceId-1', + transactionId: 'transactionId-1', + }, ]; test('`createConfigSchema()` creates correct schema.', () => { @@ -310,3 +320,40 @@ test('format() meta can not override timestamp', () => { }, }); }); + +test('format() meta can not override tracing properties', () => { + const layout = new JsonLayout(); + expect( + JSON.parse( + layout.format({ + message: 'foo', + timestamp, + level: LogLevel.Debug, + context: 'bar', + pid: 3, + meta: { + span: 'span_override', + trace: 'trace_override', + transaction: 'transaction_override', + }, + spanId: 'spanId-1', + traceId: 'traceId-1', + transactionId: 'transactionId-1', + }) + ) + ).toStrictEqual({ + ecs: { version: expect.any(String) }, + '@timestamp': '2012-02-01T09:30:22.011-05:00', + message: 'foo', + log: { + level: 'DEBUG', + logger: 'bar', + }, + process: { + pid: 3, + }, + span: { id: 'spanId-1' }, + trace: { id: 'traceId-1' }, + transaction: { id: 'transactionId-1' }, + }); +}); diff --git a/src/core/server/logging/layouts/json_layout.ts b/src/core/server/logging/layouts/json_layout.ts index f0717f49a6b15..5c23e7ac1a911 100644 --- a/src/core/server/logging/layouts/json_layout.ts +++ b/src/core/server/logging/layouts/json_layout.ts @@ -54,6 +54,9 @@ export class JsonLayout implements Layout { process: { pid: record.pid, }, + span: record.spanId ? { id: record.spanId } : undefined, + trace: record.traceId ? { id: record.traceId } : undefined, + transaction: record.transactionId ? { id: record.transactionId } : undefined, }; const output = record.meta ? merge({ ...record.meta }, log) : log; diff --git a/src/core/server/logging/logger.ts b/src/core/server/logging/logger.ts index e025c28a88f0e..2c9283da54897 100644 --- a/src/core/server/logging/logger.ts +++ b/src/core/server/logging/logger.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - +import apmAgent from 'elastic-apm-node'; import { Appender, LogLevel, LogRecord, LoggerFactory, LogMeta, Logger } from '@kbn/logging'; function isError(x: any): x is Error { @@ -73,6 +73,7 @@ export class BaseLogger implements Logger { meta, timestamp: new Date(), pid: process.pid, + ...this.getTraceIds(), }; } @@ -83,6 +84,15 @@ export class BaseLogger implements Logger { meta, timestamp: new Date(), pid: process.pid, + ...this.getTraceIds(), + }; + } + + private getTraceIds() { + return { + spanId: apmAgent.currentTraceIds['span.id'], + traceId: apmAgent.currentTraceIds['trace.id'], + transactionId: apmAgent.currentTraceIds['transaction.id'], }; } } diff --git a/vars/kibanaPipeline.groovy b/vars/kibanaPipeline.groovy index daf6ca7a8e993..8a7596a591175 100644 --- a/vars/kibanaPipeline.groovy +++ b/vars/kibanaPipeline.groovy @@ -93,7 +93,7 @@ def withFunctionalTestEnv(List additionalEnvs = [], Closure closure) { def corsTestServerPort = "64${parallelId}3" // needed for https://github.com/elastic/kibana/issues/107246 def proxyTestServerPort = "64${parallelId}4" - def apmActive = githubPr.isPr() ? "false" : "true" + def contextPropagationOnly = githubPr.isPr() ? "true" : "false" withEnv([ "CI_GROUP=${parallelId}", @@ -109,7 +109,8 @@ def withFunctionalTestEnv(List additionalEnvs = [], Closure closure) { "KBN_NP_PLUGINS_BUILT=true", "FLEET_PACKAGE_REGISTRY_PORT=${fleetPackageRegistryPort}", "ALERTING_PROXY_PORT=${alertingProxyPort}", - "ELASTIC_APM_ACTIVE=${apmActive}", + "ELASTIC_APM_ACTIVE=true", + "ELASTIC_APM_CONTEXT_PROPAGATION_ONLY=${contextPropagationOnly}", "ELASTIC_APM_TRANSACTION_SAMPLE_RATE=0.1", ] + additionalEnvs) { closure() diff --git a/x-pack/test/functional_execution_context/config.ts b/x-pack/test/functional_execution_context/config.ts index f841e8957cde3..456d31b586ad0 100644 --- a/x-pack/test/functional_execution_context/config.ts +++ b/x-pack/test/functional_execution_context/config.ts @@ -42,6 +42,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { `--elasticsearch.hosts=${servers.elasticsearch.protocol}://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`, `--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`, + '--server.requestId.allowFromAnyIp=true', '--execution_context.enabled=true', '--logging.appenders.file.type=file', `--logging.appenders.file.fileName=${logFilePath}`, diff --git a/x-pack/test/functional_execution_context/fixtures/plugins/alerts/server/ensure_apm_started.ts b/x-pack/test/functional_execution_context/fixtures/plugins/alerts/server/ensure_apm_started.ts new file mode 100644 index 0000000000000..8581ebe5183c1 --- /dev/null +++ b/x-pack/test/functional_execution_context/fixtures/plugins/alerts/server/ensure_apm_started.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import apmAgent from 'elastic-apm-node'; +import { initApm } from '@kbn/apm-config-loader'; +import { REPO_ROOT } from '@kbn/utils'; + +if (!apmAgent.isStarted()) { + initApm(process.argv, REPO_ROOT, false, 'test-plugin'); +} diff --git a/x-pack/test/functional_execution_context/fixtures/plugins/alerts/server/index.ts b/x-pack/test/functional_execution_context/fixtures/plugins/alerts/server/index.ts index 700aee6bfd49d..dbd04e32e860b 100644 --- a/x-pack/test/functional_execution_context/fixtures/plugins/alerts/server/index.ts +++ b/x-pack/test/functional_execution_context/fixtures/plugins/alerts/server/index.ts @@ -5,6 +5,7 @@ * 2.0. */ +import './ensure_apm_started'; import { FixturePlugin } from './plugin'; export const plugin = () => new FixturePlugin(); diff --git a/x-pack/test/functional_execution_context/fixtures/plugins/alerts/server/plugin.ts b/x-pack/test/functional_execution_context/fixtures/plugins/alerts/server/plugin.ts index 47a9e4edc30fc..ec4e3ef99c6df 100644 --- a/x-pack/test/functional_execution_context/fixtures/plugins/alerts/server/plugin.ts +++ b/x-pack/test/functional_execution_context/fixtures/plugins/alerts/server/plugin.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import apmAgent from 'elastic-apm-node'; import { Plugin, CoreSetup } from 'kibana/server'; import { PluginSetupContract as AlertingPluginSetup } from '../../../../../../plugins/alerting/server/plugin'; @@ -81,6 +82,32 @@ export class FixturePlugin implements Plugin { + const transaction = apmAgent.startTransaction(); + const subscription = req.events.completed$.subscribe(() => { + transaction?.end(); + subscription.unsubscribe(); + }); + + await ctx.core.elasticsearch.client.asInternalUser.ping(); + + return res.ok({ + body: { + traceId: apmAgent.currentTraceIds['trace.id'], + }, + }); + } + ); } public start() {} diff --git a/x-pack/test/functional_execution_context/tests/index.ts b/x-pack/test/functional_execution_context/tests/index.ts index 6d74a94608671..c092be9bd8bdb 100644 --- a/x-pack/test/functional_execution_context/tests/index.ts +++ b/x-pack/test/functional_execution_context/tests/index.ts @@ -12,5 +12,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { this.tags('ciGroup1'); loadTestFile(require.resolve('./browser')); loadTestFile(require.resolve('./server')); + loadTestFile(require.resolve('./log_correlation')); }); } diff --git a/x-pack/test/functional_execution_context/tests/log_correlation.ts b/x-pack/test/functional_execution_context/tests/log_correlation.ts new file mode 100644 index 0000000000000..80bb2285a665e --- /dev/null +++ b/x-pack/test/functional_execution_context/tests/log_correlation.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import expect from '@kbn/expect'; +import type { FtrProviderContext } from '../ftr_provider_context'; +import { assertLogContains } from '../test_utils'; + +export default function ({ getService }: FtrProviderContext) { + const retry = getService('retry'); + const supertest = getService('supertest'); + + describe('Log Correlation', () => { + it('Emits "trace.id" into the logs', async () => { + const response1 = await supertest + .get('/emit_log_with_trace_id') + .set('x-opaque-id', 'myheader1'); + + expect(response1.body.traceId).to.be.a('string'); + + const response2 = await supertest.get('/emit_log_with_trace_id'); + expect(response1.body.traceId).to.be.a('string'); + + expect(response2.body.traceId).not.to.be(response1.body.traceId); + + await assertLogContains({ + description: 'traceId included in the Kibana logs', + predicate: (record) => + // we don't check trace.id value since trace.id in the test plugin and Kibana are different on CI. + // because different 'elastic-apm-node' instaces are imported + Boolean(record.http?.request?.id?.includes('myheader1') && record.trace?.id), + retry, + }); + }); + }); +} diff --git a/x-pack/test/performance/config.ts b/x-pack/test/performance/config.ts index 89b7b52e28670..82586ee62ad80 100644 --- a/x-pack/test/performance/config.ts +++ b/x-pack/test/performance/config.ts @@ -32,6 +32,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { ...functionalConfig.get('kbnTestServer'), env: { ELASTIC_APM_ACTIVE: 'true', + ELASTIC_APM_CONTEXT_PROPAGATION_ONLY: 'false', ELASTIC_APM_ENVIRONMENT: process.env.CI ? 'ci' : 'development', ELASTIC_APM_TRANSACTION_SAMPLE_RATE: '1.0', ELASTIC_APM_SERVER_URL: APM_SERVER_URL, diff --git a/yarn.lock b/yarn.lock index 7c2f64a0983b9..533f1cbd89456 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13225,10 +13225,10 @@ ejs@^3.1.2, ejs@^3.1.6: dependencies: jake "^10.6.1" -elastic-apm-http-client@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/elastic-apm-http-client/-/elastic-apm-http-client-10.1.0.tgz#8fbfa3f026f40d82b22b77bf4ed539cc20623edb" - integrity sha512-G+UsOQS8+kTyjbZ9PBXgbN8RGgeTe3FfbVljiwuN+eIf0UwpSR8k5Oh+Z2BELTTVwTcit7NCH4+B4MPayYx1mw== +elastic-apm-http-client@^10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/elastic-apm-http-client/-/elastic-apm-http-client-10.3.0.tgz#12b95dc190a755cd1a8ce2c296cd28ef50f16aa4" + integrity sha512-BAqB7k5JA/x09L8BVj04WRoknRptmW2rLAoHQVrPvPhUm/IgNz63wPfiBuhWVE//Hl7xEpURO5pMV6az0UArkA== dependencies: breadth-filter "^2.0.0" container-info "^1.0.1" @@ -13239,10 +13239,10 @@ elastic-apm-http-client@^10.1.0: readable-stream "^3.4.0" stream-chopper "^3.0.1" -elastic-apm-node@^3.23.0: - version "3.23.0" - resolved "https://registry.yarnpkg.com/elastic-apm-node/-/elastic-apm-node-3.23.0.tgz#e842aa505d576003579803e45fe91f572db74a72" - integrity sha512-yzdO/MwAcjT+TbcBQBKWbDb4beDVmmrIaFCu9VA+z6Ow9GKlQv7QaD9/cQjuN8/KI6ASiJfQI8cPgqy1SgSUuA== +elastic-apm-node@3.24.0: + version "3.24.0" + resolved "https://registry.yarnpkg.com/elastic-apm-node/-/elastic-apm-node-3.24.0.tgz#d7acb3352f928a23c28ebabab2bd30098562814e" + integrity sha512-Fmj/W2chWQa2zb1FfMYK2ypLB4TcnKNX+1klaJFbytRYDLgeSfo0EC7egvI3a+bLPZSRL5053PXOp7slVTPO6Q== dependencies: "@elastic/ecs-pino-format" "^1.2.0" after-all-results "^2.0.0" @@ -13251,7 +13251,7 @@ elastic-apm-node@^3.23.0: basic-auth "^2.0.1" cookie "^0.4.0" core-util-is "^1.0.2" - elastic-apm-http-client "^10.1.0" + elastic-apm-http-client "^10.3.0" end-of-stream "^1.4.4" error-callsites "^2.0.4" error-stack-parser "^2.0.6" From 4c1e629ca62b617a0278c271b2f414382ba001e7 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Thu, 11 Nov 2021 14:30:37 +0300 Subject: [PATCH 42/51] [Lens] Expose Elasticsearch accuracy warnings to the user (#116632) * [Lens] Expose Elasticsearch accuracy warnings to the user Closes: #94918 * fix comments * update text Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- ...-plugin-core-public.doclinksstart.links.md | 1 + ...kibana-plugin-core-public.doclinksstart.md | 2 +- .../public/doc_links/doc_links_service.ts | 2 + src/core/public/public.api.md | 1 + .../data/common/search/aggs/agg_type.ts | 5 ++ .../common/search/aggs/buckets/terms.test.ts | 12 +++ .../data/common/search/aggs/buckets/terms.ts | 1 + .../data/common/search/tabify/index.ts | 1 + .../search/tabify/response_writer.test.ts | 4 + .../common/search/tabify/response_writer.ts | 3 +- .../data/common/search/tabify/tabify.ts | 8 +- .../data/common/search/tabify/types.ts | 1 + .../data/common/search/tabify/utils.test.ts | 46 ++++++++++++ .../data/common/search/tabify/utils.ts | 13 ++++ src/plugins/data/public/index.ts | 2 + src/plugins/data/public/search/index.ts | 1 + .../snapshots/baseline/combined_test2.json | 2 +- .../snapshots/baseline/combined_test3.json | 2 +- .../snapshots/baseline/final_output_test.json | 2 +- .../snapshots/baseline/metric_all_data.json | 2 +- .../snapshots/baseline/metric_empty_data.json | 2 +- .../baseline/metric_multi_metric_data.json | 2 +- .../baseline/metric_percentage_mode.json | 2 +- .../baseline/metric_single_metric_data.json | 2 +- .../snapshots/baseline/partial_test_1.json | 2 +- .../snapshots/baseline/partial_test_2.json | 2 +- .../snapshots/baseline/step_output_test2.json | 2 +- .../snapshots/baseline/step_output_test3.json | 2 +- .../snapshots/baseline/tagcloud_all_data.json | 2 +- .../baseline/tagcloud_empty_data.json | 2 +- .../snapshots/baseline/tagcloud_fontsize.json | 2 +- .../baseline/tagcloud_metric_data.json | 2 +- .../snapshots/baseline/tagcloud_options.json | 2 +- .../snapshots/session/combined_test0.json | 1 - .../snapshots/session/combined_test1.json | 1 - .../snapshots/session/combined_test2.json | 1 - .../snapshots/session/combined_test3.json | 1 - .../snapshots/session/final_output_test.json | 1 - .../snapshots/session/metric_all_data.json | 1 - .../snapshots/session/metric_empty_data.json | 1 - .../session/metric_invalid_data.json | 1 - .../session/metric_multi_metric_data.json | 1 - .../session/metric_percentage_mode.json | 1 - .../session/metric_single_metric_data.json | 1 - .../snapshots/session/partial_test_1.json | 1 - .../snapshots/session/partial_test_2.json | 1 - .../snapshots/session/step_output_test0.json | 1 - .../snapshots/session/step_output_test1.json | 1 - .../snapshots/session/step_output_test2.json | 1 - .../snapshots/session/step_output_test3.json | 1 - .../snapshots/session/tagcloud_all_data.json | 1 - .../session/tagcloud_empty_data.json | 1 - .../snapshots/session/tagcloud_fontsize.json | 1 - .../session/tagcloud_invalid_data.json | 1 - .../session/tagcloud_metric_data.json | 1 - .../snapshots/session/tagcloud_options.json | 1 - .../indexpattern.test.ts | 48 +++++++++--- .../indexpattern_datasource/indexpattern.tsx | 9 ++- .../indexpattern_datasource/utils.test.tsx | 61 +++++++++++++++ .../{utils.ts => utils.tsx} | 74 ++++++++++++++++++- 60 files changed, 293 insertions(+), 59 deletions(-) create mode 100644 src/plugins/data/common/search/tabify/utils.test.ts create mode 100644 src/plugins/data/common/search/tabify/utils.ts delete mode 100644 test/interpreter_functional/snapshots/session/combined_test0.json delete mode 100644 test/interpreter_functional/snapshots/session/combined_test1.json delete mode 100644 test/interpreter_functional/snapshots/session/combined_test2.json delete mode 100644 test/interpreter_functional/snapshots/session/combined_test3.json delete mode 100644 test/interpreter_functional/snapshots/session/final_output_test.json delete mode 100644 test/interpreter_functional/snapshots/session/metric_all_data.json delete mode 100644 test/interpreter_functional/snapshots/session/metric_empty_data.json delete mode 100644 test/interpreter_functional/snapshots/session/metric_invalid_data.json delete mode 100644 test/interpreter_functional/snapshots/session/metric_multi_metric_data.json delete mode 100644 test/interpreter_functional/snapshots/session/metric_percentage_mode.json delete mode 100644 test/interpreter_functional/snapshots/session/metric_single_metric_data.json delete mode 100644 test/interpreter_functional/snapshots/session/partial_test_1.json delete mode 100644 test/interpreter_functional/snapshots/session/partial_test_2.json delete mode 100644 test/interpreter_functional/snapshots/session/step_output_test0.json delete mode 100644 test/interpreter_functional/snapshots/session/step_output_test1.json delete mode 100644 test/interpreter_functional/snapshots/session/step_output_test2.json delete mode 100644 test/interpreter_functional/snapshots/session/step_output_test3.json delete mode 100644 test/interpreter_functional/snapshots/session/tagcloud_all_data.json delete mode 100644 test/interpreter_functional/snapshots/session/tagcloud_empty_data.json delete mode 100644 test/interpreter_functional/snapshots/session/tagcloud_fontsize.json delete mode 100644 test/interpreter_functional/snapshots/session/tagcloud_invalid_data.json delete mode 100644 test/interpreter_functional/snapshots/session/tagcloud_metric_data.json delete mode 100644 test/interpreter_functional/snapshots/session/tagcloud_options.json create mode 100644 x-pack/plugins/lens/public/indexpattern_datasource/utils.test.tsx rename x-pack/plugins/lens/public/indexpattern_datasource/{utils.ts => utils.tsx} (55%) diff --git a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md index 59d1f13ed89fb..37524daa39c51 100644 --- a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md +++ b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md @@ -89,6 +89,7 @@ readonly links: { readonly range: string; readonly significant_terms: string; readonly terms: string; + readonly terms_doc_count_error: string; readonly avg: string; readonly avg_bucket: string; readonly max_bucket: string; diff --git a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md index 788f0b9de8218..d0df23f35ab9e 100644 --- a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md +++ b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md @@ -17,5 +17,5 @@ export interface DocLinksStart | --- | --- | --- | | [DOC\_LINK\_VERSION](./kibana-plugin-core-public.doclinksstart.doc_link_version.md) | string | | | [ELASTIC\_WEBSITE\_URL](./kibana-plugin-core-public.doclinksstart.elastic_website_url.md) | string | | -| [links](./kibana-plugin-core-public.doclinksstart.links.md) | {
    readonly settings: string;
    readonly elasticStackGetStarted: string;
    readonly apm: {
    readonly kibanaSettings: string;
    readonly supportedServiceMaps: string;
    readonly customLinks: string;
    readonly droppedTransactionSpans: string;
    readonly upgrading: string;
    readonly metaData: string;
    };
    readonly canvas: {
    readonly guide: string;
    };
    readonly dashboard: {
    readonly guide: string;
    readonly drilldowns: string;
    readonly drilldownsTriggerPicker: string;
    readonly urlDrilldownTemplateSyntax: string;
    readonly urlDrilldownVariables: string;
    };
    readonly discover: Record<string, string>;
    readonly filebeat: {
    readonly base: string;
    readonly installation: string;
    readonly configuration: string;
    readonly elasticsearchOutput: string;
    readonly elasticsearchModule: string;
    readonly startup: string;
    readonly exportedFields: string;
    readonly suricataModule: string;
    readonly zeekModule: string;
    };
    readonly auditbeat: {
    readonly base: string;
    readonly auditdModule: string;
    readonly systemModule: string;
    };
    readonly metricbeat: {
    readonly base: string;
    readonly configure: string;
    readonly httpEndpoint: string;
    readonly install: string;
    readonly start: string;
    };
    readonly enterpriseSearch: {
    readonly base: string;
    readonly appSearchBase: string;
    readonly workplaceSearchBase: string;
    };
    readonly heartbeat: {
    readonly base: string;
    };
    readonly libbeat: {
    readonly getStarted: string;
    };
    readonly logstash: {
    readonly base: string;
    };
    readonly functionbeat: {
    readonly base: string;
    };
    readonly winlogbeat: {
    readonly base: string;
    };
    readonly aggs: {
    readonly composite: string;
    readonly composite_missing_bucket: string;
    readonly date_histogram: string;
    readonly date_range: string;
    readonly date_format_pattern: string;
    readonly filter: string;
    readonly filters: string;
    readonly geohash_grid: string;
    readonly histogram: string;
    readonly ip_range: string;
    readonly range: string;
    readonly significant_terms: string;
    readonly terms: string;
    readonly avg: string;
    readonly avg_bucket: string;
    readonly max_bucket: string;
    readonly min_bucket: string;
    readonly sum_bucket: string;
    readonly cardinality: string;
    readonly count: string;
    readonly cumulative_sum: string;
    readonly derivative: string;
    readonly geo_bounds: string;
    readonly geo_centroid: string;
    readonly max: string;
    readonly median: string;
    readonly min: string;
    readonly moving_avg: string;
    readonly percentile_ranks: string;
    readonly serial_diff: string;
    readonly std_dev: string;
    readonly sum: string;
    readonly top_hits: string;
    };
    readonly runtimeFields: {
    readonly overview: string;
    readonly mapping: string;
    };
    readonly scriptedFields: {
    readonly scriptFields: string;
    readonly scriptAggs: string;
    readonly painless: string;
    readonly painlessApi: string;
    readonly painlessLangSpec: string;
    readonly painlessSyntax: string;
    readonly painlessWalkthrough: string;
    readonly luceneExpressions: string;
    };
    readonly search: {
    readonly sessions: string;
    readonly sessionLimits: string;
    };
    readonly indexPatterns: {
    readonly introduction: string;
    readonly fieldFormattersNumber: string;
    readonly fieldFormattersString: string;
    readonly runtimeFields: string;
    };
    readonly addData: string;
    readonly kibana: string;
    readonly upgradeAssistant: string;
    readonly rollupJobs: string;
    readonly elasticsearch: Record<string, string>;
    readonly siem: {
    readonly privileges: string;
    readonly guide: string;
    readonly gettingStarted: string;
    readonly ml: string;
    readonly ruleChangeLog: string;
    readonly detectionsReq: string;
    readonly networkMap: string;
    readonly troubleshootGaps: string;
    };
    readonly securitySolution: {
    readonly trustedApps: string;
    };
    readonly query: {
    readonly eql: string;
    readonly kueryQuerySyntax: string;
    readonly luceneQuerySyntax: string;
    readonly percolate: string;
    readonly queryDsl: string;
    readonly autocompleteChanges: string;
    };
    readonly date: {
    readonly dateMath: string;
    readonly dateMathIndexNames: string;
    };
    readonly management: Record<string, string>;
    readonly ml: Record<string, string>;
    readonly transforms: Record<string, string>;
    readonly visualize: Record<string, string>;
    readonly apis: Readonly<{
    bulkIndexAlias: string;
    byteSizeUnits: string;
    createAutoFollowPattern: string;
    createFollower: string;
    createIndex: string;
    createSnapshotLifecyclePolicy: string;
    createRoleMapping: string;
    createRoleMappingTemplates: string;
    createRollupJobsRequest: string;
    createApiKey: string;
    createPipeline: string;
    createTransformRequest: string;
    cronExpressions: string;
    executeWatchActionModes: string;
    indexExists: string;
    openIndex: string;
    putComponentTemplate: string;
    painlessExecute: string;
    painlessExecuteAPIContexts: string;
    putComponentTemplateMetadata: string;
    putSnapshotLifecyclePolicy: string;
    putIndexTemplateV1: string;
    putWatch: string;
    simulatePipeline: string;
    timeUnits: string;
    updateTransform: string;
    }>;
    readonly observability: Readonly<{
    guide: string;
    infrastructureThreshold: string;
    logsThreshold: string;
    metricsThreshold: string;
    monitorStatus: string;
    monitorUptime: string;
    tlsCertificate: string;
    uptimeDurationAnomaly: string;
    }>;
    readonly alerting: Record<string, string>;
    readonly maps: Record<string, string>;
    readonly monitoring: Record<string, string>;
    readonly security: Readonly<{
    apiKeyServiceSettings: string;
    clusterPrivileges: string;
    elasticsearchSettings: string;
    elasticsearchEnableSecurity: string;
    elasticsearchEnableApiKeys: string;
    indicesPrivileges: string;
    kibanaTLS: string;
    kibanaPrivileges: string;
    mappingRoles: string;
    mappingRolesFieldRules: string;
    runAsPrivilege: string;
    }>;
    readonly spaces: Readonly<{
    kibanaLegacyUrlAliases: string;
    kibanaDisableLegacyUrlAliasesApi: string;
    }>;
    readonly watcher: Record<string, string>;
    readonly ccs: Record<string, string>;
    readonly plugins: Record<string, string>;
    readonly snapshotRestore: Record<string, string>;
    readonly ingest: Record<string, string>;
    readonly fleet: Readonly<{
    datastreamsILM: string;
    beatsAgentComparison: string;
    guide: string;
    fleetServer: string;
    fleetServerAddFleetServer: string;
    settings: string;
    settingsFleetServerHostSettings: string;
    troubleshooting: string;
    elasticAgent: string;
    datastreams: string;
    datastreamsNamingScheme: string;
    installElasticAgent: string;
    upgradeElasticAgent: string;
    upgradeElasticAgent712lower: string;
    learnMoreBlog: string;
    apiKeysLearnMore: string;
    }>;
    readonly ecs: {
    readonly guide: string;
    };
    readonly clients: {
    readonly guide: string;
    readonly goOverview: string;
    readonly javaIndex: string;
    readonly jsIntro: string;
    readonly netGuide: string;
    readonly perlGuide: string;
    readonly phpGuide: string;
    readonly pythonGuide: string;
    readonly rubyOverview: string;
    readonly rustGuide: string;
    };
    readonly endpoints: {
    readonly troubleshooting: string;
    };
    } | | +| [links](./kibana-plugin-core-public.doclinksstart.links.md) | {
    readonly settings: string;
    readonly elasticStackGetStarted: string;
    readonly apm: {
    readonly kibanaSettings: string;
    readonly supportedServiceMaps: string;
    readonly customLinks: string;
    readonly droppedTransactionSpans: string;
    readonly upgrading: string;
    readonly metaData: string;
    };
    readonly canvas: {
    readonly guide: string;
    };
    readonly dashboard: {
    readonly guide: string;
    readonly drilldowns: string;
    readonly drilldownsTriggerPicker: string;
    readonly urlDrilldownTemplateSyntax: string;
    readonly urlDrilldownVariables: string;
    };
    readonly discover: Record<string, string>;
    readonly filebeat: {
    readonly base: string;
    readonly installation: string;
    readonly configuration: string;
    readonly elasticsearchOutput: string;
    readonly elasticsearchModule: string;
    readonly startup: string;
    readonly exportedFields: string;
    readonly suricataModule: string;
    readonly zeekModule: string;
    };
    readonly auditbeat: {
    readonly base: string;
    readonly auditdModule: string;
    readonly systemModule: string;
    };
    readonly metricbeat: {
    readonly base: string;
    readonly configure: string;
    readonly httpEndpoint: string;
    readonly install: string;
    readonly start: string;
    };
    readonly enterpriseSearch: {
    readonly base: string;
    readonly appSearchBase: string;
    readonly workplaceSearchBase: string;
    };
    readonly heartbeat: {
    readonly base: string;
    };
    readonly libbeat: {
    readonly getStarted: string;
    };
    readonly logstash: {
    readonly base: string;
    };
    readonly functionbeat: {
    readonly base: string;
    };
    readonly winlogbeat: {
    readonly base: string;
    };
    readonly aggs: {
    readonly composite: string;
    readonly composite_missing_bucket: string;
    readonly date_histogram: string;
    readonly date_range: string;
    readonly date_format_pattern: string;
    readonly filter: string;
    readonly filters: string;
    readonly geohash_grid: string;
    readonly histogram: string;
    readonly ip_range: string;
    readonly range: string;
    readonly significant_terms: string;
    readonly terms: string;
    readonly terms_doc_count_error: string;
    readonly avg: string;
    readonly avg_bucket: string;
    readonly max_bucket: string;
    readonly min_bucket: string;
    readonly sum_bucket: string;
    readonly cardinality: string;
    readonly count: string;
    readonly cumulative_sum: string;
    readonly derivative: string;
    readonly geo_bounds: string;
    readonly geo_centroid: string;
    readonly max: string;
    readonly median: string;
    readonly min: string;
    readonly moving_avg: string;
    readonly percentile_ranks: string;
    readonly serial_diff: string;
    readonly std_dev: string;
    readonly sum: string;
    readonly top_hits: string;
    };
    readonly runtimeFields: {
    readonly overview: string;
    readonly mapping: string;
    };
    readonly scriptedFields: {
    readonly scriptFields: string;
    readonly scriptAggs: string;
    readonly painless: string;
    readonly painlessApi: string;
    readonly painlessLangSpec: string;
    readonly painlessSyntax: string;
    readonly painlessWalkthrough: string;
    readonly luceneExpressions: string;
    };
    readonly search: {
    readonly sessions: string;
    readonly sessionLimits: string;
    };
    readonly indexPatterns: {
    readonly introduction: string;
    readonly fieldFormattersNumber: string;
    readonly fieldFormattersString: string;
    readonly runtimeFields: string;
    };
    readonly addData: string;
    readonly kibana: string;
    readonly upgradeAssistant: string;
    readonly rollupJobs: string;
    readonly elasticsearch: Record<string, string>;
    readonly siem: {
    readonly privileges: string;
    readonly guide: string;
    readonly gettingStarted: string;
    readonly ml: string;
    readonly ruleChangeLog: string;
    readonly detectionsReq: string;
    readonly networkMap: string;
    readonly troubleshootGaps: string;
    };
    readonly securitySolution: {
    readonly trustedApps: string;
    };
    readonly query: {
    readonly eql: string;
    readonly kueryQuerySyntax: string;
    readonly luceneQuerySyntax: string;
    readonly percolate: string;
    readonly queryDsl: string;
    readonly autocompleteChanges: string;
    };
    readonly date: {
    readonly dateMath: string;
    readonly dateMathIndexNames: string;
    };
    readonly management: Record<string, string>;
    readonly ml: Record<string, string>;
    readonly transforms: Record<string, string>;
    readonly visualize: Record<string, string>;
    readonly apis: Readonly<{
    bulkIndexAlias: string;
    byteSizeUnits: string;
    createAutoFollowPattern: string;
    createFollower: string;
    createIndex: string;
    createSnapshotLifecyclePolicy: string;
    createRoleMapping: string;
    createRoleMappingTemplates: string;
    createRollupJobsRequest: string;
    createApiKey: string;
    createPipeline: string;
    createTransformRequest: string;
    cronExpressions: string;
    executeWatchActionModes: string;
    indexExists: string;
    openIndex: string;
    putComponentTemplate: string;
    painlessExecute: string;
    painlessExecuteAPIContexts: string;
    putComponentTemplateMetadata: string;
    putSnapshotLifecyclePolicy: string;
    putIndexTemplateV1: string;
    putWatch: string;
    simulatePipeline: string;
    timeUnits: string;
    updateTransform: string;
    }>;
    readonly observability: Readonly<{
    guide: string;
    infrastructureThreshold: string;
    logsThreshold: string;
    metricsThreshold: string;
    monitorStatus: string;
    monitorUptime: string;
    tlsCertificate: string;
    uptimeDurationAnomaly: string;
    }>;
    readonly alerting: Record<string, string>;
    readonly maps: Record<string, string>;
    readonly monitoring: Record<string, string>;
    readonly security: Readonly<{
    apiKeyServiceSettings: string;
    clusterPrivileges: string;
    elasticsearchSettings: string;
    elasticsearchEnableSecurity: string;
    elasticsearchEnableApiKeys: string;
    indicesPrivileges: string;
    kibanaTLS: string;
    kibanaPrivileges: string;
    mappingRoles: string;
    mappingRolesFieldRules: string;
    runAsPrivilege: string;
    }>;
    readonly spaces: Readonly<{
    kibanaLegacyUrlAliases: string;
    kibanaDisableLegacyUrlAliasesApi: string;
    }>;
    readonly watcher: Record<string, string>;
    readonly ccs: Record<string, string>;
    readonly plugins: Record<string, string>;
    readonly snapshotRestore: Record<string, string>;
    readonly ingest: Record<string, string>;
    readonly fleet: Readonly<{
    datastreamsILM: string;
    beatsAgentComparison: string;
    guide: string;
    fleetServer: string;
    fleetServerAddFleetServer: string;
    settings: string;
    settingsFleetServerHostSettings: string;
    troubleshooting: string;
    elasticAgent: string;
    datastreams: string;
    datastreamsNamingScheme: string;
    installElasticAgent: string;
    upgradeElasticAgent: string;
    upgradeElasticAgent712lower: string;
    learnMoreBlog: string;
    apiKeysLearnMore: string;
    }>;
    readonly ecs: {
    readonly guide: string;
    };
    readonly clients: {
    readonly guide: string;
    readonly goOverview: string;
    readonly javaIndex: string;
    readonly jsIntro: string;
    readonly netGuide: string;
    readonly perlGuide: string;
    readonly phpGuide: string;
    readonly pythonGuide: string;
    readonly rubyOverview: string;
    readonly rustGuide: string;
    };
    readonly endpoints: {
    readonly troubleshooting: string;
    };
    } | | diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index 41bf27c7706a9..ee4e50627074a 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -118,6 +118,7 @@ export class DocLinksService { range: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-range-aggregation.html`, significant_terms: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-significantterms-aggregation.html`, terms: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-terms-aggregation.html`, + terms_doc_count_error: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-terms-aggregation.html#_per_bucket_document_count_error`, avg: `${ELASTICSEARCH_DOCS}search-aggregations-metrics-avg-aggregation.html`, avg_bucket: `${ELASTICSEARCH_DOCS}search-aggregations-pipeline-avg-bucket-aggregation.html`, max_bucket: `${ELASTICSEARCH_DOCS}search-aggregations-pipeline-max-bucket-aggregation.html`, @@ -613,6 +614,7 @@ export interface DocLinksStart { readonly range: string; readonly significant_terms: string; readonly terms: string; + readonly terms_doc_count_error: string; readonly avg: string; readonly avg_bucket: string; readonly max_bucket: string; diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 26df3ee28d5c5..67edf0cf37614 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -557,6 +557,7 @@ export interface DocLinksStart { readonly range: string; readonly significant_terms: string; readonly terms: string; + readonly terms_doc_count_error: string; readonly avg: string; readonly avg_bucket: string; readonly max_bucket: string; diff --git a/src/plugins/data/common/search/aggs/agg_type.ts b/src/plugins/data/common/search/aggs/agg_type.ts index 917f80d3b7819..3f91eadd19eb4 100644 --- a/src/plugins/data/common/search/aggs/agg_type.ts +++ b/src/plugins/data/common/search/aggs/agg_type.ts @@ -53,6 +53,7 @@ export interface AggTypeConfig< json?: boolean; decorateAggConfig?: () => any; postFlightRequest?: PostFlightRequestFn; + hasPrecisionError?: (aggBucket: Record) => boolean; getSerializedFormat?: (agg: TAggConfig) => SerializedFieldFormat; getValue?: (agg: TAggConfig, bucket: any) => any; getKey?: (bucket: any, key: any, agg: TAggConfig) => any; @@ -180,6 +181,9 @@ export class AggType< * is created, giving the agg type a chance to modify the agg config */ decorateAggConfig: () => any; + + hasPrecisionError?: (aggBucket: Record) => boolean; + /** * A function that needs to be called after the main request has been made * and should return an updated response @@ -283,6 +287,7 @@ export class AggType< this.getResponseAggs = config.getResponseAggs || (() => {}); this.decorateAggConfig = config.decorateAggConfig || (() => ({})); this.postFlightRequest = config.postFlightRequest || identity; + this.hasPrecisionError = config.hasPrecisionError; this.getSerializedFormat = config.getSerializedFormat || diff --git a/src/plugins/data/common/search/aggs/buckets/terms.test.ts b/src/plugins/data/common/search/aggs/buckets/terms.test.ts index 50aa4eb2b0357..524606f7c562f 100644 --- a/src/plugins/data/common/search/aggs/buckets/terms.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/terms.test.ts @@ -286,7 +286,19 @@ describe('Terms Agg', () => { { typesRegistry: mockAggTypesRegistry() } ); const { [BUCKET_TYPES.TERMS]: params } = aggConfigs.aggs[0].toDsl(); + expect(params.order).toEqual({ 'test-orderAgg.50': 'desc' }); }); + + test('should override "hasPrecisionError" for the "terms" bucket type', () => { + const aggConfigs = getAggConfigs(); + const { type } = aggConfigs.aggs[0]; + + expect(type.hasPrecisionError).toBeInstanceOf(Function); + + expect(type.hasPrecisionError!({})).toBeFalsy(); + expect(type.hasPrecisionError!({ doc_count_error_upper_bound: 0 })).toBeFalsy(); + expect(type.hasPrecisionError!({ doc_count_error_upper_bound: -1 })).toBeTruthy(); + }); }); }); diff --git a/src/plugins/data/common/search/aggs/buckets/terms.ts b/src/plugins/data/common/search/aggs/buckets/terms.ts index b9329bcb25af3..b3872d29beaac 100644 --- a/src/plugins/data/common/search/aggs/buckets/terms.ts +++ b/src/plugins/data/common/search/aggs/buckets/terms.ts @@ -85,6 +85,7 @@ export const getTermsBucketAgg = () => }; }, createFilter: createFilterTerms, + hasPrecisionError: (aggBucket) => Boolean(aggBucket?.doc_count_error_upper_bound), postFlightRequest: async ( resp, aggConfigs, diff --git a/src/plugins/data/common/search/tabify/index.ts b/src/plugins/data/common/search/tabify/index.ts index 279ff705f231c..3a4b094826e78 100644 --- a/src/plugins/data/common/search/tabify/index.ts +++ b/src/plugins/data/common/search/tabify/index.ts @@ -9,3 +9,4 @@ export { tabifyDocs, flattenHit } from './tabify_docs'; export { tabifyAggResponse } from './tabify'; export { tabifyGetColumns } from './get_columns'; +export { checkColumnForPrecisionError } from './utils'; diff --git a/src/plugins/data/common/search/tabify/response_writer.test.ts b/src/plugins/data/common/search/tabify/response_writer.test.ts index 603ccc0f493c7..cee297d255db3 100644 --- a/src/plugins/data/common/search/tabify/response_writer.test.ts +++ b/src/plugins/data/common/search/tabify/response_writer.test.ts @@ -166,6 +166,7 @@ describe('TabbedAggResponseWriter class', () => { field: 'geo.src', source: 'esaggs', sourceParams: { + hasPrecisionError: false, enabled: true, id: '1', indexPatternId: '1234', @@ -193,6 +194,7 @@ describe('TabbedAggResponseWriter class', () => { }, source: 'esaggs', sourceParams: { + hasPrecisionError: false, appliedTimeRange: undefined, enabled: true, id: '2', @@ -227,6 +229,7 @@ describe('TabbedAggResponseWriter class', () => { field: 'geo.src', source: 'esaggs', sourceParams: { + hasPrecisionError: false, enabled: true, id: '1', indexPatternId: '1234', @@ -254,6 +257,7 @@ describe('TabbedAggResponseWriter class', () => { }, source: 'esaggs', sourceParams: { + hasPrecisionError: false, appliedTimeRange: undefined, enabled: true, id: '2', diff --git a/src/plugins/data/common/search/tabify/response_writer.ts b/src/plugins/data/common/search/tabify/response_writer.ts index a0ba07598e53a..6af0576b9ed4d 100644 --- a/src/plugins/data/common/search/tabify/response_writer.ts +++ b/src/plugins/data/common/search/tabify/response_writer.ts @@ -10,7 +10,7 @@ import { isEmpty } from 'lodash'; import { IAggConfigs } from '../aggs'; import { tabifyGetColumns } from './get_columns'; -import { TabbedResponseWriterOptions, TabbedAggColumn, TabbedAggRow } from './types'; +import type { TabbedResponseWriterOptions, TabbedAggColumn, TabbedAggRow } from './types'; import { Datatable, DatatableColumn } from '../../../../expressions/common/expression_types/specs'; interface BufferColumn { @@ -80,6 +80,7 @@ export class TabbedAggResponseWriter { params: column.aggConfig.toSerializedFieldFormat(), source: 'esaggs', sourceParams: { + hasPrecisionError: Boolean(column.hasPrecisionError), indexPatternId: column.aggConfig.getIndexPattern()?.id, appliedTimeRange: column.aggConfig.params.field?.name && diff --git a/src/plugins/data/common/search/tabify/tabify.ts b/src/plugins/data/common/search/tabify/tabify.ts index a4d9551da75d5..d3273accff974 100644 --- a/src/plugins/data/common/search/tabify/tabify.ts +++ b/src/plugins/data/common/search/tabify/tabify.ts @@ -42,8 +42,14 @@ export function tabifyAggResponse( switch (agg.type.type) { case AggGroupNames.Buckets: - const aggBucket = get(bucket, agg.id); + const aggBucket = get(bucket, agg.id) as Record; const tabifyBuckets = new TabifyBuckets(aggBucket, agg.params, respOpts?.timeRange); + const precisionError = agg.type.hasPrecisionError?.(aggBucket); + + if (precisionError) { + // "сolumn" mutation, we have to do this here as this value is filled in based on aggBucket value + column.hasPrecisionError = true; + } if (tabifyBuckets.length) { tabifyBuckets.forEach((subBucket, tabifyBucketKey) => { diff --git a/src/plugins/data/common/search/tabify/types.ts b/src/plugins/data/common/search/tabify/types.ts index 758a2dfb181f2..9fadb0ef860e3 100644 --- a/src/plugins/data/common/search/tabify/types.ts +++ b/src/plugins/data/common/search/tabify/types.ts @@ -41,6 +41,7 @@ export interface TabbedAggColumn { aggConfig: IAggConfig; id: string; name: string; + hasPrecisionError?: boolean; } /** @public **/ diff --git a/src/plugins/data/common/search/tabify/utils.test.ts b/src/plugins/data/common/search/tabify/utils.test.ts new file mode 100644 index 0000000000000..ed29ef58ec0bf --- /dev/null +++ b/src/plugins/data/common/search/tabify/utils.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { checkColumnForPrecisionError } from './utils'; +import type { DatatableColumn } from '../../../../expressions'; + +describe('tabify utils', () => { + describe('checkDatatableForPrecisionError', () => { + test('should return true if there is a precision error in the column', () => { + expect( + checkColumnForPrecisionError({ + meta: { + sourceParams: { + hasPrecisionError: true, + }, + }, + } as unknown as DatatableColumn) + ).toBeTruthy(); + }); + test('should return false if there is no precision error in the column', () => { + expect( + checkColumnForPrecisionError({ + meta: { + sourceParams: { + hasPrecisionError: false, + }, + }, + } as unknown as DatatableColumn) + ).toBeFalsy(); + }); + test('should return false if precision error is not defined', () => { + expect( + checkColumnForPrecisionError({ + meta: { + sourceParams: {}, + }, + } as unknown as DatatableColumn) + ).toBeFalsy(); + }); + }); +}); diff --git a/src/plugins/data/common/search/tabify/utils.ts b/src/plugins/data/common/search/tabify/utils.ts new file mode 100644 index 0000000000000..1a4f87e2fed73 --- /dev/null +++ b/src/plugins/data/common/search/tabify/utils.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { DatatableColumn } from '../../../../expressions'; + +/** @public **/ +export const checkColumnForPrecisionError = (column: DatatableColumn) => + column.meta.sourceParams?.hasPrecisionError; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 0b749d90f7152..a54a9c7f35e3f 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -139,6 +139,7 @@ import { // tabify tabifyAggResponse, tabifyGetColumns, + checkColumnForPrecisionError, } from '../common'; export { AggGroupLabels, AggGroupNames, METRIC_TYPES, BUCKET_TYPES } from '../common'; @@ -246,6 +247,7 @@ export const search = { getResponseInspectorStats, tabifyAggResponse, tabifyGetColumns, + checkColumnForPrecisionError, }; /* diff --git a/src/plugins/data/public/search/index.ts b/src/plugins/data/public/search/index.ts index 821f16e0cf68a..2cd7993e3b183 100644 --- a/src/plugins/data/public/search/index.ts +++ b/src/plugins/data/public/search/index.ts @@ -36,6 +36,7 @@ export { parseSearchSourceJSON, SearchSource, SortDirection, + checkColumnForPrecisionError, } from '../../common/search'; export type { ISessionService, diff --git a/test/interpreter_functional/snapshots/baseline/combined_test2.json b/test/interpreter_functional/snapshots/baseline/combined_test2.json index 4870694e6adbc..3b030ec8fb597 100644 --- a/test/interpreter_functional/snapshots/baseline/combined_test2.json +++ b/test/interpreter_functional/snapshots/baseline/combined_test2.json @@ -1 +1 @@ -{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"} \ No newline at end of file +{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/combined_test3.json b/test/interpreter_functional/snapshots/baseline/combined_test3.json index 8e6d59933716d..2ddf40eb79006 100644 --- a/test/interpreter_functional/snapshots/baseline/combined_test3.json +++ b/test/interpreter_functional/snapshots/baseline/combined_test3.json @@ -1 +1 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/final_output_test.json b/test/interpreter_functional/snapshots/baseline/final_output_test.json index 8e6d59933716d..2ddf40eb79006 100644 --- a/test/interpreter_functional/snapshots/baseline/final_output_test.json +++ b/test/interpreter_functional/snapshots/baseline/final_output_test.json @@ -1 +1 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_all_data.json b/test/interpreter_functional/snapshots/baseline/metric_all_data.json index f176dfdb83e5c..fb16bf98ce761 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_all_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_all_data.json @@ -1 +1 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_empty_data.json b/test/interpreter_functional/snapshots/baseline/metric_empty_data.json index f9df8409edfcb..d667cc6088a3a 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_empty_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_empty_data.json @@ -1 +1 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json b/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json index ab19a031e8c71..6ef90caf3da3e 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json @@ -1 +1 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json b/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json index 2112c5bccf507..bc1ec6278dc32 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json +++ b/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json @@ -1 +1 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":{"colors":["rgb(0,0,0,0)","rgb(100, 100, 100)"],"continuity":"none","gradient":false,"range":"number","rangeMax":10000,"rangeMin":0,"stops":[0,10000]},"percentageMode":true,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":{"colors":["rgb(0,0,0,0)","rgb(100, 100, 100)"],"continuity":"none","gradient":false,"range":"number","rangeMax":10000,"rangeMin":0,"stops":[0,10000]},"percentageMode":true,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json b/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json index 6bacc8f885e1b..b5cc75694b4ba 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json @@ -1 +1 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/partial_test_1.json b/test/interpreter_functional/snapshots/baseline/partial_test_1.json index 9877a0d3138c0..5b081f4d0713e 100644 --- a/test/interpreter_functional/snapshots/baseline/partial_test_1.json +++ b/test/interpreter_functional/snapshots/baseline/partial_test_1.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/partial_test_2.json b/test/interpreter_functional/snapshots/baseline/partial_test_2.json index 8e6d59933716d..2ddf40eb79006 100644 --- a/test/interpreter_functional/snapshots/baseline/partial_test_2.json +++ b/test/interpreter_functional/snapshots/baseline/partial_test_2.json @@ -1 +1 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/step_output_test2.json b/test/interpreter_functional/snapshots/baseline/step_output_test2.json index 4870694e6adbc..3b030ec8fb597 100644 --- a/test/interpreter_functional/snapshots/baseline/step_output_test2.json +++ b/test/interpreter_functional/snapshots/baseline/step_output_test2.json @@ -1 +1 @@ -{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"} \ No newline at end of file +{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/step_output_test3.json b/test/interpreter_functional/snapshots/baseline/step_output_test3.json index 8e6d59933716d..2ddf40eb79006 100644 --- a/test/interpreter_functional/snapshots/baseline/step_output_test3.json +++ b/test/interpreter_functional/snapshots/baseline/step_output_test3.json @@ -1 +1 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json b/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json index 5ddf081c54d95..8f079b49ed98d 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_empty_data.json b/test/interpreter_functional/snapshots/baseline/tagcloud_empty_data.json index 723ebb6e9f460..e0026b189949d 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_empty_data.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_empty_data.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json b/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json index 1655451d41d03..4eef2bcb1fc48 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json b/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json index f0bfd56ac99b8..26ca82acd7563 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_options.json b/test/interpreter_functional/snapshots/baseline/tagcloud_options.json index ba034fa2e435a..d13cc180e1e7d 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_options.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_options.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"log","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"log","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/combined_test0.json b/test/interpreter_functional/snapshots/session/combined_test0.json deleted file mode 100644 index 8f00d72df8ab3..0000000000000 --- a/test/interpreter_functional/snapshots/session/combined_test0.json +++ /dev/null @@ -1 +0,0 @@ -{"filters":[],"query":[],"timeRange":null,"type":"kibana_context"} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/combined_test1.json b/test/interpreter_functional/snapshots/session/combined_test1.json deleted file mode 100644 index 8f00d72df8ab3..0000000000000 --- a/test/interpreter_functional/snapshots/session/combined_test1.json +++ /dev/null @@ -1 +0,0 @@ -{"filters":[],"query":[],"timeRange":null,"type":"kibana_context"} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/combined_test2.json b/test/interpreter_functional/snapshots/session/combined_test2.json deleted file mode 100644 index 4870694e6adbc..0000000000000 --- a/test/interpreter_functional/snapshots/session/combined_test2.json +++ /dev/null @@ -1 +0,0 @@ -{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/combined_test3.json b/test/interpreter_functional/snapshots/session/combined_test3.json deleted file mode 100644 index 8e6d59933716d..0000000000000 --- a/test/interpreter_functional/snapshots/session/combined_test3.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/final_output_test.json b/test/interpreter_functional/snapshots/session/final_output_test.json deleted file mode 100644 index 8e6d59933716d..0000000000000 --- a/test/interpreter_functional/snapshots/session/final_output_test.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_all_data.json b/test/interpreter_functional/snapshots/session/metric_all_data.json deleted file mode 100644 index f176dfdb83e5c..0000000000000 --- a/test/interpreter_functional/snapshots/session/metric_all_data.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_empty_data.json b/test/interpreter_functional/snapshots/session/metric_empty_data.json deleted file mode 100644 index f9df8409edfcb..0000000000000 --- a/test/interpreter_functional/snapshots/session/metric_empty_data.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_invalid_data.json b/test/interpreter_functional/snapshots/session/metric_invalid_data.json deleted file mode 100644 index f23b9b0915774..0000000000000 --- a/test/interpreter_functional/snapshots/session/metric_invalid_data.json +++ /dev/null @@ -1 +0,0 @@ -"[metricVis] > [visdimension] > Column name or index provided is invalid" \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json b/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json deleted file mode 100644 index ab19a031e8c71..0000000000000 --- a/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_percentage_mode.json b/test/interpreter_functional/snapshots/session/metric_percentage_mode.json deleted file mode 100644 index 2112c5bccf507..0000000000000 --- a/test/interpreter_functional/snapshots/session/metric_percentage_mode.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":{"colors":["rgb(0,0,0,0)","rgb(100, 100, 100)"],"continuity":"none","gradient":false,"range":"number","rangeMax":10000,"rangeMin":0,"stops":[0,10000]},"percentageMode":true,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_single_metric_data.json b/test/interpreter_functional/snapshots/session/metric_single_metric_data.json deleted file mode 100644 index 6bacc8f885e1b..0000000000000 --- a/test/interpreter_functional/snapshots/session/metric_single_metric_data.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/partial_test_1.json b/test/interpreter_functional/snapshots/session/partial_test_1.json deleted file mode 100644 index 9877a0d3138c0..0000000000000 --- a/test/interpreter_functional/snapshots/session/partial_test_1.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/partial_test_2.json b/test/interpreter_functional/snapshots/session/partial_test_2.json deleted file mode 100644 index 8e6d59933716d..0000000000000 --- a/test/interpreter_functional/snapshots/session/partial_test_2.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/step_output_test0.json b/test/interpreter_functional/snapshots/session/step_output_test0.json deleted file mode 100644 index 8f00d72df8ab3..0000000000000 --- a/test/interpreter_functional/snapshots/session/step_output_test0.json +++ /dev/null @@ -1 +0,0 @@ -{"filters":[],"query":[],"timeRange":null,"type":"kibana_context"} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/step_output_test1.json b/test/interpreter_functional/snapshots/session/step_output_test1.json deleted file mode 100644 index 8f00d72df8ab3..0000000000000 --- a/test/interpreter_functional/snapshots/session/step_output_test1.json +++ /dev/null @@ -1 +0,0 @@ -{"filters":[],"query":[],"timeRange":null,"type":"kibana_context"} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/step_output_test2.json b/test/interpreter_functional/snapshots/session/step_output_test2.json deleted file mode 100644 index 4870694e6adbc..0000000000000 --- a/test/interpreter_functional/snapshots/session/step_output_test2.json +++ /dev/null @@ -1 +0,0 @@ -{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/step_output_test3.json b/test/interpreter_functional/snapshots/session/step_output_test3.json deleted file mode 100644 index 8e6d59933716d..0000000000000 --- a/test/interpreter_functional/snapshots/session/step_output_test3.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_all_data.json b/test/interpreter_functional/snapshots/session/tagcloud_all_data.json deleted file mode 100644 index 5ddf081c54d95..0000000000000 --- a/test/interpreter_functional/snapshots/session/tagcloud_all_data.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_empty_data.json b/test/interpreter_functional/snapshots/session/tagcloud_empty_data.json deleted file mode 100644 index 723ebb6e9f460..0000000000000 --- a/test/interpreter_functional/snapshots/session/tagcloud_empty_data.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json b/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json deleted file mode 100644 index 1655451d41d03..0000000000000 --- a/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_invalid_data.json b/test/interpreter_functional/snapshots/session/tagcloud_invalid_data.json deleted file mode 100644 index b5ae1a2cb59fc..0000000000000 --- a/test/interpreter_functional/snapshots/session/tagcloud_invalid_data.json +++ /dev/null @@ -1 +0,0 @@ -"[tagcloud] > [visdimension] > Column name or index provided is invalid" \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json b/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json deleted file mode 100644 index f0bfd56ac99b8..0000000000000 --- a/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_options.json b/test/interpreter_functional/snapshots/session/tagcloud_options.json deleted file mode 100644 index ba034fa2e435a..0000000000000 --- a/test/interpreter_functional/snapshots/session/tagcloud_options.json +++ /dev/null @@ -1 +0,0 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"log","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts index 5a405bb2328eb..8f180d4a021e0 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts @@ -1345,8 +1345,11 @@ describe('IndexPattern Data Source', () => { }); describe('#getWarningMessages', () => { - it('should return mismatched time shifts', () => { - const state: IndexPatternPrivateState = { + let state: IndexPatternPrivateState; + let framePublicAPI: FramePublicAPI; + + beforeEach(() => { + state = { indexPatternRefs: [], existingFields: {}, isFirstExistenceFetch: false, @@ -1410,7 +1413,8 @@ describe('IndexPattern Data Source', () => { }, currentIndexPatternId: '1', }; - const warnings = indexPatternDatasource.getWarningMessages!(state, { + + framePublicAPI = { activeData: { first: { type: 'datatable', @@ -1433,20 +1437,39 @@ describe('IndexPattern Data Source', () => { ], }, }, - } as unknown as FramePublicAPI); - expect(warnings!.length).toBe(2); - expect((warnings![0] as React.ReactElement).props.id).toEqual( - 'xpack.lens.indexPattern.timeShiftSmallWarning' - ); - expect((warnings![1] as React.ReactElement).props.id).toEqual( - 'xpack.lens.indexPattern.timeShiftMultipleWarning' - ); + } as unknown as FramePublicAPI; + }); + + it('should return mismatched time shifts', () => { + const warnings = indexPatternDatasource.getWarningMessages!(state, framePublicAPI); + + expect(warnings!.map((item) => (item as React.ReactElement).props.id)).toMatchInlineSnapshot(` + Array [ + "xpack.lens.indexPattern.timeShiftSmallWarning", + "xpack.lens.indexPattern.timeShiftMultipleWarning", + ] + `); + }); + + it('should show different types of warning messages', () => { + framePublicAPI.activeData!.first.columns[0].meta.sourceParams!.hasPrecisionError = true; + + const warnings = indexPatternDatasource.getWarningMessages!(state, framePublicAPI); + + expect(warnings!.map((item) => (item as React.ReactElement).props.id)).toMatchInlineSnapshot(` + Array [ + "xpack.lens.indexPattern.timeShiftSmallWarning", + "xpack.lens.indexPattern.timeShiftMultipleWarning", + "xpack.lens.indexPattern.precisionErrorWarning", + ] + `); }); it('should prepend each error with its layer number on multi-layer chart', () => { (getErrorMessages as jest.Mock).mockClear(); (getErrorMessages as jest.Mock).mockReturnValueOnce(['error 1', 'error 2']); - const state: IndexPatternPrivateState = { + + state = { indexPatternRefs: [], existingFields: {}, isFirstExistenceFetch: false, @@ -1465,6 +1488,7 @@ describe('IndexPattern Data Source', () => { }, currentIndexPatternId: '1', }; + expect(indexPatternDatasource.getErrorMessages(state)).toEqual([ { longMessage: 'Layer 1 error: error 1', shortMessage: '' }, { longMessage: 'Layer 1 error: error 2', shortMessage: '' }, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx index bdcc0e621cc36..b970ad092c7f4 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx @@ -57,7 +57,7 @@ import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; import { GeoFieldWorkspacePanel } from '../editor_frame_service/editor_frame/workspace_panel/geo_field_workspace_panel'; import { DraggingIdentifier } from '../drag_drop'; import { getStateTimeShiftWarningMessages } from './time_shift_utils'; - +import { getPrecisionErrorWarningMessages } from './utils'; export type { OperationType, IndexPatternColumn } from './operations'; export { deleteColumn } from './operations'; @@ -502,7 +502,12 @@ export function getIndexPatternDatasource({ }); return messages.length ? messages : undefined; }, - getWarningMessages: getStateTimeShiftWarningMessages, + getWarningMessages: (state, frame) => { + return [ + ...(getStateTimeShiftWarningMessages(state, frame) || []), + ...getPrecisionErrorWarningMessages(state, frame, core.docLinks), + ]; + }, checkIntegrity: (state) => { const ids = Object.values(state.layers || {}).map(({ indexPatternId }) => indexPatternId); return ids.filter((id) => !state.indexPatterns[id]); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/utils.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/utils.test.tsx new file mode 100644 index 0000000000000..05be5c66fe5da --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_datasource/utils.test.tsx @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getPrecisionErrorWarningMessages } from './utils'; +import type { IndexPatternPrivateState } from './types'; +import type { FramePublicAPI } from '../types'; +import type { DocLinksStart } from 'kibana/public'; + +describe('indexpattern_datasource utils', () => { + describe('getPrecisionErrorWarningMessages', () => { + let state: IndexPatternPrivateState; + let framePublicAPI: FramePublicAPI; + let docLinks: DocLinksStart; + + beforeEach(() => { + state = {} as IndexPatternPrivateState; + framePublicAPI = { + activeData: { + id: { + columns: [ + { + meta: { + sourceParams: { + hasPrecisionError: false, + }, + }, + }, + ], + }, + }, + } as unknown as FramePublicAPI; + + docLinks = { + links: { + aggs: { + terms_doc_count_error: 'http://terms_doc_count_error', + }, + }, + } as DocLinksStart; + }); + test('should not show precisionError if hasPrecisionError is false', () => { + expect(getPrecisionErrorWarningMessages(state, framePublicAPI, docLinks)).toHaveLength(0); + }); + + test('should not show precisionError if hasPrecisionError is not defined', () => { + delete framePublicAPI.activeData!.id.columns[0].meta.sourceParams!.hasPrecisionError; + + expect(getPrecisionErrorWarningMessages(state, framePublicAPI, docLinks)).toHaveLength(0); + }); + + test('should show precisionError if hasPrecisionError is true', () => { + framePublicAPI.activeData!.id.columns[0].meta.sourceParams!.hasPrecisionError = true; + + expect(getPrecisionErrorWarningMessages(state, framePublicAPI, docLinks)).toHaveLength(1); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/utils.ts b/x-pack/plugins/lens/public/indexpattern_datasource/utils.tsx similarity index 55% rename from x-pack/plugins/lens/public/indexpattern_datasource/utils.ts rename to x-pack/plugins/lens/public/indexpattern_datasource/utils.tsx index a4e36367cef47..6d3f75a403dd7 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/utils.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/utils.tsx @@ -5,17 +5,30 @@ * 2.0. */ -import { DataType } from '../types'; -import { IndexPattern, IndexPatternLayer, DraggedField } from './types'; +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import type { DocLinksStart } from 'kibana/public'; +import { EuiLink, EuiTextColor } from '@elastic/eui'; + +import { DatatableColumn } from 'src/plugins/expressions'; +import type { DataType, FramePublicAPI } from '../types'; +import type { + IndexPattern, + IndexPatternLayer, + DraggedField, + IndexPatternPrivateState, +} from './types'; import type { BaseIndexPatternColumn, FieldBasedIndexPatternColumn, ReferenceBasedIndexPatternColumn, } from './operations/definitions/column_types'; + import { operationDefinitionMap, IndexPatternColumn } from './operations'; import { getInvalidFieldMessage } from './operations/definitions/helpers'; import { isQueryValid } from './operations/definitions/filters'; +import { checkColumnForPrecisionError } from '../../../../../src/plugins/data/common'; /** * Normalizes the specified operation type. (e.g. document operations @@ -101,3 +114,60 @@ export function fieldIsInvalid(column: IndexPatternColumn | undefined, indexPatt } return !!getInvalidFieldMessage(column, indexPattern)?.length; } + +export function getPrecisionErrorWarningMessages( + state: IndexPatternPrivateState, + { activeData }: FramePublicAPI, + docLinks: DocLinksStart +) { + const warningMessages: React.ReactNode[] = []; + + if (state && activeData) { + Object.values(activeData) + .reduce((acc: DatatableColumn[], { columns }) => [...acc, ...columns], []) + .forEach((column) => { + if (checkColumnForPrecisionError(column)) { + warningMessages.push( + {column.name}, + topValues: ( + + + + ), + filters: ( + + + + ), + link: ( + + + + ), + }} + /> + ); + } + }); + } + + return warningMessages; +} From 8d5c0ea0a35432641283f68e3bc40c68cc228cba Mon Sep 17 00:00:00 2001 From: Kate Patticha Date: Thu, 11 Nov 2021 13:16:46 +0100 Subject: [PATCH 43/51] [APM] refactor server folder by grouping router logic and colocate backend route files (#117840) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../apm/dev_docs/routing_and_linking.md | 2 +- x-pack/plugins/apm/server/index.ts | 2 +- .../create_es_client/call_async_with_debug.ts | 2 +- x-pack/plugins/apm/server/plugin.ts | 4 +- .../apm/server/routes/alerts/chart_preview.ts | 4 +- .../create_apm_server_route.ts | 2 +- .../create_apm_server_route_repository.ts | 2 +- .../get_global_apm_server_route_repository.ts | 54 +++++++++---------- .../register_apm_server_routes.test.ts} | 2 +- .../register_apm_server_routes.ts} | 0 .../get_error_rate_charts_for_backend.ts | 4 +- .../get_latency_charts_for_backend.ts | 4 +- .../backends/get_metadata_for_backend.ts | 2 +- .../get_throughput_charts_for_backend.ts | 4 +- .../backends/get_top_backends.ts | 6 +-- .../get_upstream_services_for_backend.ts | 6 +-- .../routes/{backends.ts => backends/route.ts} | 25 +++++---- .../plugins/apm/server/routes/correlations.ts | 4 +- x-pack/plugins/apm/server/routes/data_view.ts | 4 +- .../plugins/apm/server/routes/environments.ts | 4 +- x-pack/plugins/apm/server/routes/errors.ts | 4 +- .../apm/server/routes/event_metadata.ts | 4 +- .../server/routes/fallback_to_transactions.ts | 4 +- x-pack/plugins/apm/server/routes/fleet.ts | 4 +- .../server/routes/historical_data/index.ts | 4 +- .../apm/server/routes/latency_distribution.ts | 4 +- x-pack/plugins/apm/server/routes/metrics.ts | 4 +- .../server/routes/observability_overview.ts | 4 +- .../plugins/apm/server/routes/rum_client.ts | 4 +- .../plugins/apm/server/routes/service_map.ts | 4 +- .../apm/server/routes/service_nodes.ts | 4 +- x-pack/plugins/apm/server/routes/services.ts | 4 +- .../routes/settings/agent_configuration.ts | 4 +- .../routes/settings/anomaly_detection.ts | 4 +- .../apm/server/routes/settings/apm_indices.ts | 4 +- .../apm/server/routes/settings/custom_link.ts | 4 +- .../plugins/apm/server/routes/source_maps.ts | 4 +- .../plugins/apm/server/routes/suggestions.ts | 4 +- x-pack/plugins/apm/server/routes/traces.ts | 4 +- .../plugins/apm/server/routes/transactions.ts | 4 +- 40 files changed, 111 insertions(+), 106 deletions(-) rename x-pack/plugins/apm/server/routes/{ => apm_routes}/create_apm_server_route.ts (97%) rename x-pack/plugins/apm/server/routes/{ => apm_routes}/create_apm_server_route_repository.ts (97%) rename x-pack/plugins/apm/server/routes/{ => apm_routes}/get_global_apm_server_route_repository.ts (57%) rename x-pack/plugins/apm/server/routes/{register_routes/index.test.ts => apm_routes/register_apm_server_routes.test.ts} (99%) rename x-pack/plugins/apm/server/routes/{register_routes/index.ts => apm_routes/register_apm_server_routes.ts} (100%) rename x-pack/plugins/apm/server/{lib => routes}/backends/get_error_rate_charts_for_backend.ts (94%) rename x-pack/plugins/apm/server/{lib => routes}/backends/get_latency_charts_for_backend.ts (94%) rename x-pack/plugins/apm/server/{lib => routes}/backends/get_metadata_for_backend.ts (96%) rename x-pack/plugins/apm/server/{lib => routes}/backends/get_throughput_charts_for_backend.ts (95%) rename x-pack/plugins/apm/server/{lib => routes}/backends/get_top_backends.ts (78%) rename x-pack/plugins/apm/server/{lib => routes}/backends/get_upstream_services_for_backend.ts (79%) rename x-pack/plugins/apm/server/routes/{backends.ts => backends/route.ts} (89%) diff --git a/x-pack/plugins/apm/dev_docs/routing_and_linking.md b/x-pack/plugins/apm/dev_docs/routing_and_linking.md index 1f6160a6c4a99..562af3d01ef77 100644 --- a/x-pack/plugins/apm/dev_docs/routing_and_linking.md +++ b/x-pack/plugins/apm/dev_docs/routing_and_linking.md @@ -6,7 +6,7 @@ This document describes routing in the APM plugin. ### Server-side -Route definitions for APM's server-side API are in the [server/routes directory](../server/routes). Routes are created with [the `createApmServerRoute` function](../server/routes/create_apm_server_route.ts). Routes are added to the API in [the `registerRoutes` function](../server/routes/register_routes.ts), which is initialized in the plugin `setup` lifecycle method. +Route definitions for APM's server-side API are in the [server/routes directory](../server/routes). Routes are created with [the `createApmServerRoute` function](../server/routes/apm_routes/create_apm_server_route.ts). Routes are added to the API in [the `registerRoutes` function](../server/routes/apm_routes/register_apm_server_routes.ts), which is initialized in the plugin `setup` lifecycle method. The path and query string parameters are defined in the calls to `createApmServerRoute` with io-ts types, so that each route has its parameters type checked. diff --git a/x-pack/plugins/apm/server/index.ts b/x-pack/plugins/apm/server/index.ts index bd30f9e212687..416a873bac0a9 100644 --- a/x-pack/plugins/apm/server/index.ts +++ b/x-pack/plugins/apm/server/index.ts @@ -116,7 +116,7 @@ export type { APMPluginSetup } from './types'; export type { APMServerRouteRepository, APIEndpoint, -} from './routes/get_global_apm_server_route_repository'; +} from './routes/apm_routes/get_global_apm_server_route_repository'; export type { APMRouteHandlerResources } from './routes/typings'; export type { ProcessorEvent } from '../common/processor_event'; diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/call_async_with_debug.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/call_async_with_debug.ts index fb58357d68437..a9799c0cfb60c 100644 --- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/call_async_with_debug.ts +++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/call_async_with_debug.ts @@ -11,7 +11,7 @@ import chalk from 'chalk'; import { KibanaRequest } from '../../../../../../../src/core/server'; import { RequestStatus } from '../../../../../../../src/plugins/inspector'; import { WrappedElasticsearchClientError } from '../../../../../observability/server'; -import { inspectableEsQueriesMap } from '../../../routes/register_routes'; +import { inspectableEsQueriesMap } from '../../../routes/apm_routes/register_apm_server_routes'; import { getInspectResponse } from '../../../../../observability/server'; function formatObj(obj: Record) { diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts index 4e2ee4f37a8e6..b273fc867e5a8 100644 --- a/x-pack/plugins/apm/server/plugin.ts +++ b/x-pack/plugins/apm/server/plugin.ts @@ -38,8 +38,8 @@ import { APMPluginSetupDependencies, APMPluginStartDependencies, } from './types'; -import { registerRoutes } from './routes/register_routes'; -import { getGlobalApmServerRouteRepository } from './routes/get_global_apm_server_route_repository'; +import { registerRoutes } from './routes/apm_routes/register_apm_server_routes'; +import { getGlobalApmServerRouteRepository } from './routes/apm_routes/get_global_apm_server_route_repository'; import { PROCESSOR_EVENT, SERVICE_ENVIRONMENT, diff --git a/x-pack/plugins/apm/server/routes/alerts/chart_preview.ts b/x-pack/plugins/apm/server/routes/alerts/chart_preview.ts index 23a794bb7976a..cae35c7f06a85 100644 --- a/x-pack/plugins/apm/server/routes/alerts/chart_preview.ts +++ b/x-pack/plugins/apm/server/routes/alerts/chart_preview.ts @@ -10,8 +10,8 @@ import { getTransactionDurationChartPreview } from '../../lib/alerts/chart_previ import { getTransactionErrorCountChartPreview } from '../../lib/alerts/chart_preview/get_transaction_error_count'; import { getTransactionErrorRateChartPreview } from '../../lib/alerts/chart_preview/get_transaction_error_rate'; import { setupRequest } from '../../lib/helpers/setup_request'; -import { createApmServerRoute } from '../create_apm_server_route'; -import { createApmServerRouteRepository } from '../create_apm_server_route_repository'; +import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from '../apm_routes/create_apm_server_route_repository'; import { environmentRt, rangeRt } from '../default_api_types'; const alertParamsRt = t.intersection([ diff --git a/x-pack/plugins/apm/server/routes/create_apm_server_route.ts b/x-pack/plugins/apm/server/routes/apm_routes/create_apm_server_route.ts similarity index 97% rename from x-pack/plugins/apm/server/routes/create_apm_server_route.ts rename to x-pack/plugins/apm/server/routes/apm_routes/create_apm_server_route.ts index 86330a87a8c55..b00b1ad6a1fa5 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_server_route.ts +++ b/x-pack/plugins/apm/server/routes/apm_routes/create_apm_server_route.ts @@ -5,7 +5,7 @@ * 2.0. */ import { createServerRouteFactory } from '@kbn/server-route-repository'; -import { APMRouteCreateOptions, APMRouteHandlerResources } from './typings'; +import { APMRouteCreateOptions, APMRouteHandlerResources } from '../typings'; export const createApmServerRoute = createServerRouteFactory< APMRouteHandlerResources, diff --git a/x-pack/plugins/apm/server/routes/create_apm_server_route_repository.ts b/x-pack/plugins/apm/server/routes/apm_routes/create_apm_server_route_repository.ts similarity index 97% rename from x-pack/plugins/apm/server/routes/create_apm_server_route_repository.ts rename to x-pack/plugins/apm/server/routes/apm_routes/create_apm_server_route_repository.ts index b7cbe890c57db..43a5c2e33c9f8 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_server_route_repository.ts +++ b/x-pack/plugins/apm/server/routes/apm_routes/create_apm_server_route_repository.ts @@ -5,7 +5,7 @@ * 2.0. */ import { createServerRouteRepository } from '@kbn/server-route-repository'; -import { APMRouteCreateOptions, APMRouteHandlerResources } from './typings'; +import { APMRouteCreateOptions, APMRouteHandlerResources } from '../typings'; export function createApmServerRouteRepository() { return createServerRouteRepository< diff --git a/x-pack/plugins/apm/server/routes/get_global_apm_server_route_repository.ts b/x-pack/plugins/apm/server/routes/apm_routes/get_global_apm_server_route_repository.ts similarity index 57% rename from x-pack/plugins/apm/server/routes/get_global_apm_server_route_repository.ts rename to x-pack/plugins/apm/server/routes/apm_routes/get_global_apm_server_route_repository.ts index 0c5be4890ba05..fa8bc1e54ebfb 100644 --- a/x-pack/plugins/apm/server/routes/get_global_apm_server_route_repository.ts +++ b/x-pack/plugins/apm/server/routes/apm_routes/get_global_apm_server_route_repository.ts @@ -10,33 +10,33 @@ import type { EndpointOf, } from '@kbn/server-route-repository'; import { PickByValue } from 'utility-types'; -import { alertsChartPreviewRouteRepository } from './alerts/chart_preview'; -import { backendsRouteRepository } from './backends'; -import { correlationsRouteRepository } from './correlations'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; -import { environmentsRouteRepository } from './environments'; -import { errorsRouteRepository } from './errors'; -import { apmFleetRouteRepository } from './fleet'; -import { dataViewRouteRepository } from './data_view'; -import { latencyDistributionRouteRepository } from './latency_distribution'; -import { metricsRouteRepository } from './metrics'; -import { observabilityOverviewRouteRepository } from './observability_overview'; -import { rumRouteRepository } from './rum_client'; -import { fallbackToTransactionsRouteRepository } from './fallback_to_transactions'; -import { serviceRouteRepository } from './services'; -import { serviceMapRouteRepository } from './service_map'; -import { serviceNodeRouteRepository } from './service_nodes'; -import { agentConfigurationRouteRepository } from './settings/agent_configuration'; -import { anomalyDetectionRouteRepository } from './settings/anomaly_detection'; -import { apmIndicesRouteRepository } from './settings/apm_indices'; -import { customLinkRouteRepository } from './settings/custom_link'; -import { sourceMapsRouteRepository } from './source_maps'; -import { traceRouteRepository } from './traces'; -import { transactionRouteRepository } from './transactions'; -import { APMRouteHandlerResources } from './typings'; -import { historicalDataRouteRepository } from './historical_data'; -import { eventMetadataRouteRepository } from './event_metadata'; -import { suggestionsRouteRepository } from './suggestions'; +import { correlationsRouteRepository } from '../correlations'; +import { alertsChartPreviewRouteRepository } from '../alerts/chart_preview'; +import { backendsRouteRepository } from '../backends/route'; +import { createApmServerRouteRepository } from '../apm_routes/create_apm_server_route_repository'; +import { environmentsRouteRepository } from '../environments'; +import { errorsRouteRepository } from '../errors'; +import { apmFleetRouteRepository } from '../fleet'; +import { dataViewRouteRepository } from '../data_view'; +import { latencyDistributionRouteRepository } from '../latency_distribution'; +import { metricsRouteRepository } from '../metrics'; +import { observabilityOverviewRouteRepository } from '../observability_overview'; +import { rumRouteRepository } from '../rum_client'; +import { fallbackToTransactionsRouteRepository } from '../fallback_to_transactions'; +import { serviceRouteRepository } from '../services'; +import { serviceMapRouteRepository } from '../service_map'; +import { serviceNodeRouteRepository } from '../service_nodes'; +import { agentConfigurationRouteRepository } from '../settings/agent_configuration'; +import { anomalyDetectionRouteRepository } from '../settings/anomaly_detection'; +import { apmIndicesRouteRepository } from '../settings/apm_indices'; +import { customLinkRouteRepository } from '../settings/custom_link'; +import { sourceMapsRouteRepository } from '../source_maps'; +import { traceRouteRepository } from '../traces'; +import { transactionRouteRepository } from '../transactions'; +import { APMRouteHandlerResources } from '../typings'; +import { historicalDataRouteRepository } from '../historical_data'; +import { eventMetadataRouteRepository } from '../event_metadata'; +import { suggestionsRouteRepository } from '../suggestions'; const getTypedGlobalApmServerRouteRepository = () => { const repository = createApmServerRouteRepository() diff --git a/x-pack/plugins/apm/server/routes/register_routes/index.test.ts b/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.test.ts similarity index 99% rename from x-pack/plugins/apm/server/routes/register_routes/index.test.ts rename to x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.test.ts index fd554ce1f335c..371652cdab957 100644 --- a/x-pack/plugins/apm/server/routes/register_routes/index.test.ts +++ b/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.test.ts @@ -12,7 +12,7 @@ import * as t from 'io-ts'; import { CoreSetup, Logger } from 'src/core/server'; import { APMConfig } from '../..'; import { APMRouteCreateOptions, APMRouteHandlerResources } from '../typings'; -import { registerRoutes } from './index'; +import { registerRoutes } from './register_apm_server_routes'; type RegisterRouteDependencies = Parameters[0]; diff --git a/x-pack/plugins/apm/server/routes/register_routes/index.ts b/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.ts similarity index 100% rename from x-pack/plugins/apm/server/routes/register_routes/index.ts rename to x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.ts diff --git a/x-pack/plugins/apm/server/lib/backends/get_error_rate_charts_for_backend.ts b/x-pack/plugins/apm/server/routes/backends/get_error_rate_charts_for_backend.ts similarity index 94% rename from x-pack/plugins/apm/server/lib/backends/get_error_rate_charts_for_backend.ts rename to x-pack/plugins/apm/server/routes/backends/get_error_rate_charts_for_backend.ts index aa20b4b586335..378db134e7cf7 100644 --- a/x-pack/plugins/apm/server/lib/backends/get_error_rate_charts_for_backend.ts +++ b/x-pack/plugins/apm/server/routes/backends/get_error_rate_charts_for_backend.ts @@ -13,8 +13,8 @@ import { import { environmentQuery } from '../../../common/utils/environment_query'; import { kqlQuery, rangeQuery } from '../../../../observability/server'; import { ProcessorEvent } from '../../../common/processor_event'; -import { Setup } from '../helpers/setup_request'; -import { getMetricsDateHistogramParams } from '../helpers/metrics'; +import { Setup } from '../../lib/helpers/setup_request'; +import { getMetricsDateHistogramParams } from '../../lib/helpers/metrics'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; export async function getErrorRateChartsForBackend({ diff --git a/x-pack/plugins/apm/server/lib/backends/get_latency_charts_for_backend.ts b/x-pack/plugins/apm/server/routes/backends/get_latency_charts_for_backend.ts similarity index 94% rename from x-pack/plugins/apm/server/lib/backends/get_latency_charts_for_backend.ts rename to x-pack/plugins/apm/server/routes/backends/get_latency_charts_for_backend.ts index 9ef238fa13147..8f72d83fcc0b0 100644 --- a/x-pack/plugins/apm/server/lib/backends/get_latency_charts_for_backend.ts +++ b/x-pack/plugins/apm/server/routes/backends/get_latency_charts_for_backend.ts @@ -13,8 +13,8 @@ import { import { environmentQuery } from '../../../common/utils/environment_query'; import { kqlQuery, rangeQuery } from '../../../../observability/server'; import { ProcessorEvent } from '../../../common/processor_event'; -import { Setup } from '../helpers/setup_request'; -import { getMetricsDateHistogramParams } from '../helpers/metrics'; +import { Setup } from '../../lib/helpers/setup_request'; +import { getMetricsDateHistogramParams } from '../../lib/helpers/metrics'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; export async function getLatencyChartsForBackend({ diff --git a/x-pack/plugins/apm/server/lib/backends/get_metadata_for_backend.ts b/x-pack/plugins/apm/server/routes/backends/get_metadata_for_backend.ts similarity index 96% rename from x-pack/plugins/apm/server/lib/backends/get_metadata_for_backend.ts rename to x-pack/plugins/apm/server/routes/backends/get_metadata_for_backend.ts index 912014602dd13..1f40b975a8f9e 100644 --- a/x-pack/plugins/apm/server/lib/backends/get_metadata_for_backend.ts +++ b/x-pack/plugins/apm/server/routes/backends/get_metadata_for_backend.ts @@ -9,7 +9,7 @@ import { maybe } from '../../../common/utils/maybe'; import { ProcessorEvent } from '../../../common/processor_event'; import { SPAN_DESTINATION_SERVICE_RESOURCE } from '../../../common/elasticsearch_fieldnames'; import { rangeQuery } from '../../../../observability/server'; -import { Setup } from '../helpers/setup_request'; +import { Setup } from '../../lib/helpers/setup_request'; export async function getMetadataForBackend({ setup, diff --git a/x-pack/plugins/apm/server/lib/backends/get_throughput_charts_for_backend.ts b/x-pack/plugins/apm/server/routes/backends/get_throughput_charts_for_backend.ts similarity index 95% rename from x-pack/plugins/apm/server/lib/backends/get_throughput_charts_for_backend.ts rename to x-pack/plugins/apm/server/routes/backends/get_throughput_charts_for_backend.ts index 5a7e06683f25a..64fdc3eb264f8 100644 --- a/x-pack/plugins/apm/server/lib/backends/get_throughput_charts_for_backend.ts +++ b/x-pack/plugins/apm/server/routes/backends/get_throughput_charts_for_backend.ts @@ -12,9 +12,9 @@ import { import { environmentQuery } from '../../../common/utils/environment_query'; import { kqlQuery, rangeQuery } from '../../../../observability/server'; import { ProcessorEvent } from '../../../common/processor_event'; -import { Setup } from '../helpers/setup_request'; +import { Setup } from '../../lib/helpers/setup_request'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; -import { getBucketSize } from '../helpers/get_bucket_size'; +import { getBucketSize } from '../../lib/helpers/get_bucket_size'; export async function getThroughputChartsForBackend({ backendName, diff --git a/x-pack/plugins/apm/server/lib/backends/get_top_backends.ts b/x-pack/plugins/apm/server/routes/backends/get_top_backends.ts similarity index 78% rename from x-pack/plugins/apm/server/lib/backends/get_top_backends.ts rename to x-pack/plugins/apm/server/routes/backends/get_top_backends.ts index 15fb58345e5c0..7251718396660 100644 --- a/x-pack/plugins/apm/server/lib/backends/get_top_backends.ts +++ b/x-pack/plugins/apm/server/routes/backends/get_top_backends.ts @@ -8,9 +8,9 @@ import { kqlQuery } from '../../../../observability/server'; import { NodeType } from '../../../common/connections'; import { environmentQuery } from '../../../common/utils/environment_query'; -import { getConnectionStats } from '../connections/get_connection_stats'; -import { getConnectionStatsItemsWithRelativeImpact } from '../connections/get_connection_stats/get_connection_stats_items_with_relative_impact'; -import { Setup } from '../helpers/setup_request'; +import { getConnectionStats } from '../../lib/connections/get_connection_stats'; +import { getConnectionStatsItemsWithRelativeImpact } from '../../lib/connections/get_connection_stats/get_connection_stats_items_with_relative_impact'; +import { Setup } from '../../lib/helpers/setup_request'; export async function getTopBackends({ setup, diff --git a/x-pack/plugins/apm/server/lib/backends/get_upstream_services_for_backend.ts b/x-pack/plugins/apm/server/routes/backends/get_upstream_services_for_backend.ts similarity index 79% rename from x-pack/plugins/apm/server/lib/backends/get_upstream_services_for_backend.ts rename to x-pack/plugins/apm/server/routes/backends/get_upstream_services_for_backend.ts index adc461f882216..31204c960c87d 100644 --- a/x-pack/plugins/apm/server/lib/backends/get_upstream_services_for_backend.ts +++ b/x-pack/plugins/apm/server/routes/backends/get_upstream_services_for_backend.ts @@ -8,9 +8,9 @@ import { kqlQuery } from '../../../../observability/server'; import { SPAN_DESTINATION_SERVICE_RESOURCE } from '../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../common/utils/environment_query'; -import { getConnectionStats } from '../connections/get_connection_stats'; -import { getConnectionStatsItemsWithRelativeImpact } from '../connections/get_connection_stats/get_connection_stats_items_with_relative_impact'; -import { Setup } from '../helpers/setup_request'; +import { getConnectionStats } from '../../lib/connections/get_connection_stats'; +import { getConnectionStatsItemsWithRelativeImpact } from '../../lib/connections/get_connection_stats/get_connection_stats_items_with_relative_impact'; +import { Setup } from '../../lib/helpers/setup_request'; export async function getUpstreamServicesForBackend({ setup, diff --git a/x-pack/plugins/apm/server/routes/backends.ts b/x-pack/plugins/apm/server/routes/backends/route.ts similarity index 89% rename from x-pack/plugins/apm/server/routes/backends.ts rename to x-pack/plugins/apm/server/routes/backends/route.ts index 4dcd8a1db9575..58160477994bd 100644 --- a/x-pack/plugins/apm/server/routes/backends.ts +++ b/x-pack/plugins/apm/server/routes/backends/route.ts @@ -7,16 +7,21 @@ import * as t from 'io-ts'; import { toNumberRt } from '@kbn/io-ts-utils/to_number_rt'; -import { setupRequest } from '../lib/helpers/setup_request'; -import { environmentRt, kueryRt, offsetRt, rangeRt } from './default_api_types'; -import { createApmServerRoute } from './create_apm_server_route'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; -import { getMetadataForBackend } from '../lib/backends/get_metadata_for_backend'; -import { getLatencyChartsForBackend } from '../lib/backends/get_latency_charts_for_backend'; -import { getTopBackends } from '../lib/backends/get_top_backends'; -import { getUpstreamServicesForBackend } from '../lib/backends/get_upstream_services_for_backend'; -import { getThroughputChartsForBackend } from '../lib/backends/get_throughput_charts_for_backend'; -import { getErrorRateChartsForBackend } from '../lib/backends/get_error_rate_charts_for_backend'; +import { setupRequest } from '../../lib/helpers/setup_request'; +import { + environmentRt, + kueryRt, + offsetRt, + rangeRt, +} from '../default_api_types'; +import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from '../apm_routes/create_apm_server_route_repository'; +import { getMetadataForBackend } from './get_metadata_for_backend'; +import { getLatencyChartsForBackend } from './get_latency_charts_for_backend'; +import { getTopBackends } from './get_top_backends'; +import { getUpstreamServicesForBackend } from './get_upstream_services_for_backend'; +import { getThroughputChartsForBackend } from './get_throughput_charts_for_backend'; +import { getErrorRateChartsForBackend } from './get_error_rate_charts_for_backend'; const topBackendsRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/backends/top_backends', diff --git a/x-pack/plugins/apm/server/routes/correlations.ts b/x-pack/plugins/apm/server/routes/correlations.ts index ac6835fdd6474..f6ca064b4385f 100644 --- a/x-pack/plugins/apm/server/routes/correlations.ts +++ b/x-pack/plugins/apm/server/routes/correlations.ts @@ -24,8 +24,8 @@ import { fetchFieldsStats } from '../lib/correlations/queries/field_stats/get_fi import { withApmSpan } from '../utils/with_apm_span'; -import { createApmServerRoute } from './create_apm_server_route'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; import { environmentRt, kueryRt, rangeRt } from './default_api_types'; const INVALID_LICENSE = i18n.translate('xpack.apm.correlations.license.text', { diff --git a/x-pack/plugins/apm/server/routes/data_view.ts b/x-pack/plugins/apm/server/routes/data_view.ts index 5b06b51078ec7..3590ef9db9bd0 100644 --- a/x-pack/plugins/apm/server/routes/data_view.ts +++ b/x-pack/plugins/apm/server/routes/data_view.ts @@ -6,10 +6,10 @@ */ import { createStaticDataView } from '../lib/data_view/create_static_data_view'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; import { setupRequest } from '../lib/helpers/setup_request'; import { getDynamicDataView } from '../lib/data_view/get_dynamic_data_view'; -import { createApmServerRoute } from './create_apm_server_route'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; const staticDataViewRoute = createApmServerRoute({ endpoint: 'POST /internal/apm/data_view/static', diff --git a/x-pack/plugins/apm/server/routes/environments.ts b/x-pack/plugins/apm/server/routes/environments.ts index e54ad79f177c4..38328a63a411e 100644 --- a/x-pack/plugins/apm/server/routes/environments.ts +++ b/x-pack/plugins/apm/server/routes/environments.ts @@ -11,8 +11,8 @@ import { getSearchAggregatedTransactions } from '../lib/helpers/transactions'; import { setupRequest } from '../lib/helpers/setup_request'; import { getEnvironments } from '../lib/environments/get_environments'; import { rangeRt } from './default_api_types'; -import { createApmServerRoute } from './create_apm_server_route'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; const environmentsRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/environments', diff --git a/x-pack/plugins/apm/server/routes/errors.ts b/x-pack/plugins/apm/server/routes/errors.ts index 3a6e07acd14bc..02df03f108083 100644 --- a/x-pack/plugins/apm/server/routes/errors.ts +++ b/x-pack/plugins/apm/server/routes/errors.ts @@ -6,7 +6,7 @@ */ import * as t from 'io-ts'; -import { createApmServerRoute } from './create_apm_server_route'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; import { getErrorDistribution } from '../lib/errors/distribution/get_distribution'; import { getErrorGroupSample } from '../lib/errors/get_error_group_sample'; import { getErrorGroups } from '../lib/errors/get_error_groups'; @@ -17,7 +17,7 @@ import { rangeRt, comparisonRangeRt, } from './default_api_types'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; const errorsRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/services/{serviceName}/errors', diff --git a/x-pack/plugins/apm/server/routes/event_metadata.ts b/x-pack/plugins/apm/server/routes/event_metadata.ts index 00241d2ef1c68..3a40e445007ee 100644 --- a/x-pack/plugins/apm/server/routes/event_metadata.ts +++ b/x-pack/plugins/apm/server/routes/event_metadata.ts @@ -6,8 +6,8 @@ */ import * as t from 'io-ts'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; -import { createApmServerRoute } from './create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; import { getEventMetadata } from '../lib/event_metadata/get_event_metadata'; import { processorEventRt } from '../../common/processor_event'; import { setupRequest } from '../lib/helpers/setup_request'; diff --git a/x-pack/plugins/apm/server/routes/fallback_to_transactions.ts b/x-pack/plugins/apm/server/routes/fallback_to_transactions.ts index 99c6a290e34b1..53e3ebae0d4ff 100644 --- a/x-pack/plugins/apm/server/routes/fallback_to_transactions.ts +++ b/x-pack/plugins/apm/server/routes/fallback_to_transactions.ts @@ -8,8 +8,8 @@ import * as t from 'io-ts'; import { getIsUsingTransactionEvents } from '../lib/helpers/transactions/get_is_using_transaction_events'; import { setupRequest } from '../lib/helpers/setup_request'; -import { createApmServerRoute } from './create_apm_server_route'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; import { kueryRt, rangeRt } from './default_api_types'; const fallbackToTransactionsRoute = createApmServerRoute({ diff --git a/x-pack/plugins/apm/server/routes/fleet.ts b/x-pack/plugins/apm/server/routes/fleet.ts index e18aefcd6e0d8..a6e0cb09d894a 100644 --- a/x-pack/plugins/apm/server/routes/fleet.ts +++ b/x-pack/plugins/apm/server/routes/fleet.ts @@ -24,8 +24,8 @@ import { getUnsupportedApmServerSchema } from '../lib/fleet/get_unsupported_apm_ import { isSuperuser } from '../lib/fleet/is_superuser'; import { getInternalSavedObjectsClient } from '../lib/helpers/get_internal_saved_objects_client'; import { setupRequest } from '../lib/helpers/setup_request'; -import { createApmServerRoute } from './create_apm_server_route'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; const hasFleetDataRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/fleet/has_data', diff --git a/x-pack/plugins/apm/server/routes/historical_data/index.ts b/x-pack/plugins/apm/server/routes/historical_data/index.ts index fb67dc4f5b649..f488669fffa11 100644 --- a/x-pack/plugins/apm/server/routes/historical_data/index.ts +++ b/x-pack/plugins/apm/server/routes/historical_data/index.ts @@ -6,8 +6,8 @@ */ import { setupRequest } from '../../lib/helpers/setup_request'; -import { createApmServerRoute } from '../create_apm_server_route'; -import { createApmServerRouteRepository } from '../create_apm_server_route_repository'; +import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from '../apm_routes/create_apm_server_route_repository'; import { hasHistoricalAgentData } from './has_historical_agent_data'; const hasDataRoute = createApmServerRoute({ diff --git a/x-pack/plugins/apm/server/routes/latency_distribution.ts b/x-pack/plugins/apm/server/routes/latency_distribution.ts index ba646c0fc92bb..826898784835e 100644 --- a/x-pack/plugins/apm/server/routes/latency_distribution.ts +++ b/x-pack/plugins/apm/server/routes/latency_distribution.ts @@ -9,8 +9,8 @@ import * as t from 'io-ts'; import { toNumberRt } from '@kbn/io-ts-utils/to_number_rt'; import { getOverallLatencyDistribution } from '../lib/latency/get_overall_latency_distribution'; import { setupRequest } from '../lib/helpers/setup_request'; -import { createApmServerRoute } from './create_apm_server_route'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; import { environmentRt, kueryRt, rangeRt } from './default_api_types'; const latencyOverallDistributionRoute = createApmServerRoute({ diff --git a/x-pack/plugins/apm/server/routes/metrics.ts b/x-pack/plugins/apm/server/routes/metrics.ts index 8b6b16a26f1d8..1817c3e1546bd 100644 --- a/x-pack/plugins/apm/server/routes/metrics.ts +++ b/x-pack/plugins/apm/server/routes/metrics.ts @@ -8,8 +8,8 @@ import * as t from 'io-ts'; import { setupRequest } from '../lib/helpers/setup_request'; import { getMetricsChartDataByAgent } from '../lib/metrics/get_metrics_chart_data_by_agent'; -import { createApmServerRoute } from './create_apm_server_route'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; import { environmentRt, kueryRt, rangeRt } from './default_api_types'; const metricsChartsRoute = createApmServerRoute({ diff --git a/x-pack/plugins/apm/server/routes/observability_overview.ts b/x-pack/plugins/apm/server/routes/observability_overview.ts index b4fb4804a9bda..2df3212d8da70 100644 --- a/x-pack/plugins/apm/server/routes/observability_overview.ts +++ b/x-pack/plugins/apm/server/routes/observability_overview.ts @@ -14,8 +14,8 @@ import { getHasData } from '../lib/observability_overview/has_data'; import { rangeRt } from './default_api_types'; import { getSearchAggregatedTransactions } from '../lib/helpers/transactions'; import { withApmSpan } from '../utils/with_apm_span'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; -import { createApmServerRoute } from './create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; const observabilityOverviewHasDataRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/observability_overview/has_data', diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts index c465e0e02da1c..45f8d9f6149ff 100644 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -19,8 +19,8 @@ import { getUrlSearch } from '../lib/rum_client/get_url_search'; import { getVisitorBreakdown } from '../lib/rum_client/get_visitor_breakdown'; import { getWebCoreVitals } from '../lib/rum_client/get_web_core_vitals'; import { hasRumData } from '../lib/rum_client/has_rum_data'; -import { createApmServerRoute } from './create_apm_server_route'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; import { rangeRt } from './default_api_types'; import { UxUIFilters } from '../../typings/ui_filters'; import { APMRouteHandlerResources } from '../routes/typings'; diff --git a/x-pack/plugins/apm/server/routes/service_map.ts b/x-pack/plugins/apm/server/routes/service_map.ts index 3711ee20d814b..e75b4ec832d82 100644 --- a/x-pack/plugins/apm/server/routes/service_map.ts +++ b/x-pack/plugins/apm/server/routes/service_map.ts @@ -15,8 +15,8 @@ import { setupRequest } from '../lib/helpers/setup_request'; import { getServiceMap } from '../lib/service_map/get_service_map'; import { getServiceMapBackendNodeInfo } from '../lib/service_map/get_service_map_backend_node_info'; import { getServiceMapServiceNodeInfo } from '../lib/service_map/get_service_map_service_node_info'; -import { createApmServerRoute } from './create_apm_server_route'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; import { environmentRt, rangeRt } from './default_api_types'; const serviceMapRoute = createApmServerRoute({ diff --git a/x-pack/plugins/apm/server/routes/service_nodes.ts b/x-pack/plugins/apm/server/routes/service_nodes.ts index 2081b794f8ab1..61d58bfa3cf38 100644 --- a/x-pack/plugins/apm/server/routes/service_nodes.ts +++ b/x-pack/plugins/apm/server/routes/service_nodes.ts @@ -6,8 +6,8 @@ */ import * as t from 'io-ts'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; -import { createApmServerRoute } from './create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; import { setupRequest } from '../lib/helpers/setup_request'; import { getServiceNodes } from '../lib/service_nodes'; import { rangeRt, kueryRt } from './default_api_types'; diff --git a/x-pack/plugins/apm/server/routes/services.ts b/x-pack/plugins/apm/server/routes/services.ts index 60036a9a3da76..cb557f56d8165 100644 --- a/x-pack/plugins/apm/server/routes/services.ts +++ b/x-pack/plugins/apm/server/routes/services.ts @@ -34,8 +34,8 @@ import { getServiceProfilingStatistics } from '../lib/services/profiling/get_ser import { getServiceProfilingTimeline } from '../lib/services/profiling/get_service_profiling_timeline'; import { getServiceInfrastructure } from '../lib/services/get_service_infrastructure'; import { withApmSpan } from '../utils/with_apm_span'; -import { createApmServerRoute } from './create_apm_server_route'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; import { comparisonRangeRt, environmentRt, diff --git a/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts b/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts index 5385cd74cd779..563fa40c6c0d9 100644 --- a/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts +++ b/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts @@ -17,7 +17,7 @@ import { findExactConfiguration } from '../../lib/settings/agent_configuration/f import { listConfigurations } from '../../lib/settings/agent_configuration/list_configurations'; import { getEnvironments } from '../../lib/settings/agent_configuration/get_environments'; import { deleteConfiguration } from '../../lib/settings/agent_configuration/delete_configuration'; -import { createApmServerRoute } from '../create_apm_server_route'; +import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { getAgentNameByService } from '../../lib/settings/agent_configuration/get_agent_name_by_service'; import { markAppliedByAgent } from '../../lib/settings/agent_configuration/mark_applied_by_agent'; import { @@ -25,7 +25,7 @@ import { agentConfigurationIntakeRt, } from '../../../common/agent_configuration/runtime_types/agent_configuration_intake_rt'; import { getSearchAggregatedTransactions } from '../../lib/helpers/transactions'; -import { createApmServerRouteRepository } from '../create_apm_server_route_repository'; +import { createApmServerRouteRepository } from '../apm_routes/create_apm_server_route_repository'; import { syncAgentConfigsToApmPackagePolicies } from '../../lib/fleet/sync_agent_configs_to_apm_package_policies'; // get list of configurations diff --git a/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts b/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts index f614f35810c57..e8b2ef5e119cd 100644 --- a/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts +++ b/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts @@ -10,7 +10,7 @@ import Boom from '@hapi/boom'; import { maxSuggestions } from '../../../../observability/common'; import { isActivePlatinumLicense } from '../../../common/license_check'; import { ML_ERRORS } from '../../../common/anomaly_detection'; -import { createApmServerRoute } from '../create_apm_server_route'; +import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { getAnomalyDetectionJobs } from '../../lib/anomaly_detection/get_anomaly_detection_jobs'; import { createAnomalyDetectionJobs } from '../../lib/anomaly_detection/create_anomaly_detection_jobs'; import { setupRequest } from '../../lib/helpers/setup_request'; @@ -19,7 +19,7 @@ import { hasLegacyJobs } from '../../lib/anomaly_detection/has_legacy_jobs'; import { getSearchAggregatedTransactions } from '../../lib/helpers/transactions'; import { notifyFeatureUsage } from '../../feature'; import { withApmSpan } from '../../utils/with_apm_span'; -import { createApmServerRouteRepository } from '../create_apm_server_route_repository'; +import { createApmServerRouteRepository } from '../apm_routes/create_apm_server_route_repository'; // get ML anomaly detection jobs for each environment const anomalyDetectionJobsRoute = createApmServerRoute({ diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices.ts b/x-pack/plugins/apm/server/routes/settings/apm_indices.ts index 156f4d1af0bb2..ed99f0c8862f0 100644 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices.ts +++ b/x-pack/plugins/apm/server/routes/settings/apm_indices.ts @@ -6,8 +6,8 @@ */ import * as t from 'io-ts'; -import { createApmServerRouteRepository } from '../create_apm_server_route_repository'; -import { createApmServerRoute } from '../create_apm_server_route'; +import { createApmServerRouteRepository } from '../apm_routes/create_apm_server_route_repository'; +import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { getApmIndices, getApmIndexSettings, diff --git a/x-pack/plugins/apm/server/routes/settings/custom_link.ts b/x-pack/plugins/apm/server/routes/settings/custom_link.ts index af880898176bb..044b56c3c273d 100644 --- a/x-pack/plugins/apm/server/routes/settings/custom_link.ts +++ b/x-pack/plugins/apm/server/routes/settings/custom_link.ts @@ -21,8 +21,8 @@ import { import { deleteCustomLink } from '../../lib/settings/custom_link/delete_custom_link'; import { getTransaction } from '../../lib/settings/custom_link/get_transaction'; import { listCustomLinks } from '../../lib/settings/custom_link/list_custom_links'; -import { createApmServerRoute } from '../create_apm_server_route'; -import { createApmServerRouteRepository } from '../create_apm_server_route_repository'; +import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from '../apm_routes/create_apm_server_route_repository'; const customLinkTransactionRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/settings/custom_links/transaction', diff --git a/x-pack/plugins/apm/server/routes/source_maps.ts b/x-pack/plugins/apm/server/routes/source_maps.ts index d009b68c6919b..602a3a725eac4 100644 --- a/x-pack/plugins/apm/server/routes/source_maps.ts +++ b/x-pack/plugins/apm/server/routes/source_maps.ts @@ -16,8 +16,8 @@ import { getCleanedBundleFilePath, } from '../lib/fleet/source_maps'; import { getInternalSavedObjectsClient } from '../lib/helpers/get_internal_saved_objects_client'; -import { createApmServerRoute } from './create_apm_server_route'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; import { stringFromBufferRt } from '../utils/string_from_buffer_rt'; export const sourceMapRt = t.intersection([ diff --git a/x-pack/plugins/apm/server/routes/suggestions.ts b/x-pack/plugins/apm/server/routes/suggestions.ts index 4834d894f364a..9b8952d09d162 100644 --- a/x-pack/plugins/apm/server/routes/suggestions.ts +++ b/x-pack/plugins/apm/server/routes/suggestions.ts @@ -10,8 +10,8 @@ import { maxSuggestions } from '../../../observability/common'; import { getSuggestions } from '../lib/suggestions/get_suggestions'; import { getSearchAggregatedTransactions } from '../lib/helpers/transactions'; import { setupRequest } from '../lib/helpers/setup_request'; -import { createApmServerRoute } from './create_apm_server_route'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; const suggestionsRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/suggestions', diff --git a/x-pack/plugins/apm/server/routes/traces.ts b/x-pack/plugins/apm/server/routes/traces.ts index cc800c348b165..5fdac470a81ed 100644 --- a/x-pack/plugins/apm/server/routes/traces.ts +++ b/x-pack/plugins/apm/server/routes/traces.ts @@ -9,11 +9,11 @@ import * as t from 'io-ts'; import { setupRequest } from '../lib/helpers/setup_request'; import { getTraceItems } from '../lib/traces/get_trace_items'; import { getTopTransactionGroupList } from '../lib/transaction_groups'; -import { createApmServerRoute } from './create_apm_server_route'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; import { environmentRt, kueryRt, rangeRt } from './default_api_types'; import { getSearchAggregatedTransactions } from '../lib/helpers/transactions'; import { getRootTransactionByTraceId } from '../lib/transactions/get_transaction_by_trace'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; import { getTransaction } from '../lib/transactions/get_transaction'; const tracesRoute = createApmServerRoute({ diff --git a/x-pack/plugins/apm/server/routes/transactions.ts b/x-pack/plugins/apm/server/routes/transactions.ts index 4f4ca7eb1ba85..c0d83bac6e8e4 100644 --- a/x-pack/plugins/apm/server/routes/transactions.ts +++ b/x-pack/plugins/apm/server/routes/transactions.ts @@ -21,8 +21,8 @@ import { getTransactionTraceSamples } from '../lib/transactions/trace_samples'; import { getAnomalySeries } from '../lib/transactions/get_anomaly_data'; import { getLatencyPeriods } from '../lib/transactions/get_latency_charts'; import { getErrorRatePeriods } from '../lib/transaction_groups/get_error_rate'; -import { createApmServerRoute } from './create_apm_server_route'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; +import { createApmServerRoute } from './apm_routes/create_apm_server_route'; +import { createApmServerRouteRepository } from './apm_routes/create_apm_server_route_repository'; import { comparisonRangeRt, environmentRt, From 532610b4cbf593a1df69bd075498f3fcfa8e1e05 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 11 Nov 2021 13:17:19 +0100 Subject: [PATCH 44/51] [Reporting] Fix browser diagnostic Jest test flakiness (#118003) * mock and reduce the wait time for reading diagnoistic logs * remove comment * run test suite 42 times - REVERT THIS * Revert "run test suite 42 times - REVERT THIS" This reverts commit f9474aa1dbc4f215708ba6bdcb5ede1ed72411bd. * mock Rx.timer instead, revert previous solution * added comment * remove for loop Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/routes/diagnostic/browser.test.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/reporting/server/routes/diagnostic/browser.test.ts b/x-pack/plugins/reporting/server/routes/diagnostic/browser.test.ts index 7b4cc2008a676..a27ce6a49b1a2 100644 --- a/x-pack/plugins/reporting/server/routes/diagnostic/browser.test.ts +++ b/x-pack/plugins/reporting/server/routes/diagnostic/browser.test.ts @@ -10,6 +10,7 @@ import { spawn } from 'child_process'; import { createInterface } from 'readline'; import { setupServer } from 'src/core/server/test_utils'; import supertest from 'supertest'; +import * as Rx from 'rxjs'; import { ReportingCore } from '../..'; import { createMockConfigSchema, @@ -28,8 +29,10 @@ type SetupServerReturn = UnwrapPromise>; const devtoolMessage = 'DevTools listening on (ws://localhost:4000)'; const fontNotFoundMessage = 'Could not find the default font'; -// FLAKY: https://github.com/elastic/kibana/issues/89369 -describe.skip('POST /diagnose/browser', () => { +const wait = (ms: number): Rx.Observable<0> => + Rx.from(new Promise<0>((resolve) => setTimeout(() => resolve(0), ms))); + +describe('POST /diagnose/browser', () => { jest.setTimeout(6000); const reportingSymbol = Symbol('reporting'); const mockLogger = createMockLevelLogger(); @@ -53,6 +56,9 @@ describe.skip('POST /diagnose/browser', () => { () => ({ usesUiCapabilities: () => false }) ); + // Make all uses of 'Rx.timer' return an observable that completes in 50ms + jest.spyOn(Rx, 'timer').mockImplementation(() => wait(50)); + core = await createMockReportingCore( config, createMockPluginSetup({ @@ -79,6 +85,7 @@ describe.skip('POST /diagnose/browser', () => { }); afterEach(async () => { + jest.restoreAllMocks(); await server.stop(); }); From e106bf3a3cf2ba3c446f6100d3f9b655a9be4256 Mon Sep 17 00:00:00 2001 From: Oliver Gupte Date: Thu, 11 Nov 2021 07:35:02 -0500 Subject: [PATCH 45/51] [APM] Removes warning about Stack Monitoring in Fleet migration (#117086) (#118289) --- .../components/app/Settings/schema/confirm_switch_modal.tsx | 6 ------ x-pack/plugins/translations/translations/ja-JP.json | 1 - x-pack/plugins/translations/translations/zh-CN.json | 1 - 3 files changed, 8 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/Settings/schema/confirm_switch_modal.tsx b/x-pack/plugins/apm/public/components/app/Settings/schema/confirm_switch_modal.tsx index a13f31e8a6566..1847ea90bd7fa 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/schema/confirm_switch_modal.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/schema/confirm_switch_modal.tsx @@ -58,12 +58,6 @@ export function ConfirmSwitchModal({ }} confirmButtonDisabled={!isConfirmChecked} > -

    - {i18n.translate('xpack.apm.settings.schema.confirm.descriptionText', { - defaultMessage: - 'Please note Stack monitoring is not currently supported with Fleet-managed APM.', - })} -

    {!hasUnsupportedConfigs && (

    {i18n.translate( diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index ae4d25c60f695..b690a9bcdc1d8 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -6619,7 +6619,6 @@ "xpack.apm.settings.schema.confirm.apmServerSettingsCloudLinkText": "クラウドでAPMサーバー設定に移動", "xpack.apm.settings.schema.confirm.cancelText": "キャンセル", "xpack.apm.settings.schema.confirm.checkboxLabel": "データストリームに切り替えることを確認する", - "xpack.apm.settings.schema.confirm.descriptionText": "現在、スタック監視はFleetで管理されたAPMではサポートされていません。", "xpack.apm.settings.schema.confirm.irreversibleWarning.message": "移行中には一時的にAPMデータ収集に影響する可能性があります。移行プロセスは数分で完了します。", "xpack.apm.settings.schema.confirm.irreversibleWarning.title": "データストリームへの切り替えは元に戻せません。", "xpack.apm.settings.schema.confirm.switchButtonText": "データストリームに切り替える", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 9a83380158414..9a757f963523a 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -6672,7 +6672,6 @@ "xpack.apm.settings.schema.confirm.apmServerSettingsCloudLinkText": "前往 Cloud 中的 APM Server 设置", "xpack.apm.settings.schema.confirm.cancelText": "取消", "xpack.apm.settings.schema.confirm.checkboxLabel": "我确认我想切换到数据流", - "xpack.apm.settings.schema.confirm.descriptionText": "请注意 Fleet 托管的 APM 当前不支持堆栈监测。", "xpack.apm.settings.schema.confirm.irreversibleWarning.message": "迁移在进行中时,可能会暂时影响 APM 数据收集。迁移的过程应只需花费几分钟。", "xpack.apm.settings.schema.confirm.irreversibleWarning.title": "切换到数据流是不可逆的操作", "xpack.apm.settings.schema.confirm.switchButtonText": "切换到数据流", From def6d85418698b220a492a0ed175984fe158b8ba Mon Sep 17 00:00:00 2001 From: "Lucas F. da Costa" Date: Thu, 11 Nov 2021 13:12:36 +0000 Subject: [PATCH 46/51] [Uptime] [User Experience] Prefix internal apis with /internal (#117852) * [Uptime] prefix internal APIs with /internal [relates to #116334] * [Uptime] move hard-coded URL paths to rest_api constants [relates to #116334] * [Uptime] use API_URLS from constants in API integration tests [relates to #116334] * [Uptime] Remove unnecessary filters route test * [Uptime] prefix internal RUM routes with /internal and /ux [relates to #116334] * [User Experience] update API docs for prefixed internal UX APIs --- api_docs/apm.json | 54 +++++++++---------- .../RumDashboard/ClientMetrics/Metrics.tsx | 2 +- .../ImpactfulMetrics/JSErrors.tsx | 2 +- .../PageLoadDistribution/index.tsx | 2 +- .../PageLoadDistribution/use_breakdowns.ts | 2 +- .../app/RumDashboard/PageViewsTrend/index.tsx | 2 +- .../Panels/WebApplicationSelect.tsx | 2 +- .../URLFilter/URLSearch/use_url_search.tsx | 2 +- .../RumDashboard/UXMetrics/KeyUXMetrics.tsx | 2 +- .../app/RumDashboard/UXMetrics/index.tsx | 2 +- .../RumDashboard/VisitorBreakdown/index.tsx | 2 +- .../app/RumDashboard/ux_overview_fetchers.ts | 2 +- .../plugins/apm/server/routes/rum_client.ts | 20 +++---- .../uptime/common/constants/rest_api.ts | 27 ++++++---- .../columns/ping_timestamp/ping_timestamp.tsx | 2 +- .../synthetics/step_screenshot_display.tsx | 2 +- .../public/state/api/dynamic_settings.ts | 3 +- .../uptime/public/state/api/journey.ts | 13 ++--- .../uptime/public/state/api/network_events.ts | 3 +- .../uptime/public/state/api/snapshot.test.ts | 3 +- .../server/rest_api/dynamic_settings.ts | 5 +- .../network_events/get_network_events.ts | 3 +- .../pings/journey_screenshot_blocks.ts | 3 +- .../rest_api/pings/journey_screenshots.ts | 3 +- .../uptime/server/rest_api/pings/journeys.ts | 5 +- .../synthetics/last_successful_step.ts | 3 +- .../apis/uptime/get_all_pings.ts | 30 ++++++++--- .../apis/uptime/rest/dynamic_settings.ts | 11 ++-- .../apis/uptime/rest/filters.ts | 28 ---------- .../apis/uptime/rest/monitor_duration.ts | 17 +++--- .../apis/uptime/rest/monitor_latest_status.ts | 9 ++-- .../apis/uptime/rest/ping_histogram.ts | 24 +++++---- .../apis/uptime/rest/ping_list.ts | 34 ++++++++---- .../apis/uptime/rest/snapshot.ts | 15 +++--- .../tests/csm/csm_services.spec.ts | 16 +++--- .../tests/csm/js_errors.spec.ts | 20 ++++--- .../tests/csm/long_task_metrics.spec.ts | 16 +++--- .../tests/csm/page_load_dist.spec.ts | 38 ++++++++----- .../tests/csm/page_views.spec.ts | 34 +++++++----- .../tests/csm/url_search.spec.ts | 28 ++++++---- .../tests/csm/web_core_vitals.spec.ts | 18 ++++--- 41 files changed, 299 insertions(+), 210 deletions(-) delete mode 100644 x-pack/test/api_integration/apis/uptime/rest/filters.ts diff --git a/api_docs/apm.json b/api_docs/apm.json index a97e5428b2b8e..2fd290d8b9c35 100644 --- a/api_docs/apm.json +++ b/api_docs/apm.json @@ -737,7 +737,7 @@ "label": "APIEndpoint", "description": [], "signature": [ - "\"POST /internal/apm/data_view/static\" | \"GET /internal/apm/data_view/dynamic\" | \"GET /internal/apm/environments\" | \"GET /internal/apm/services/{serviceName}/errors\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}\" | \"GET /internal/apm/services/{serviceName}/errors/distribution\" | \"POST /internal/apm/latency/overall_distribution\" | \"GET /internal/apm/services/{serviceName}/metrics/charts\" | \"GET /internal/apm/observability_overview\" | \"GET /internal/apm/observability_overview/has_data\" | \"GET /api/apm/rum/client-metrics\" | \"GET /api/apm/rum-client/page-load-distribution\" | \"GET /api/apm/rum-client/page-load-distribution/breakdown\" | \"GET /api/apm/rum-client/page-view-trends\" | \"GET /api/apm/rum-client/services\" | \"GET /api/apm/rum-client/visitor-breakdown\" | \"GET /api/apm/rum-client/web-core-vitals\" | \"GET /api/apm/rum-client/long-task-metrics\" | \"GET /api/apm/rum-client/url-search\" | \"GET /api/apm/rum-client/js-errors\" | \"GET /api/apm/observability_overview/has_rum_data\" | \"GET /internal/apm/service-map\" | \"GET /internal/apm/service-map/service/{serviceName}\" | \"GET /internal/apm/service-map/backend\" | \"GET /internal/apm/services/{serviceName}/serviceNodes\" | \"GET /internal/apm/services\" | \"GET /internal/apm/services/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/metadata/details\" | \"GET /internal/apm/services/{serviceName}/metadata/icons\" | \"GET /internal/apm/services/{serviceName}/agent\" | \"GET /internal/apm/services/{serviceName}/transaction_types\" | \"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\" | \"GET /api/apm/services/{serviceName}/annotation/search\" | \"POST /api/apm/services/{serviceName}/annotation\" | \"GET /internal/apm/services/{serviceName}/error_groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/error_groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\" | \"GET /internal/apm/services/{serviceName}/throughput\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/dependencies\" | \"GET /internal/apm/services/{serviceName}/dependencies/breakdown\" | \"GET /internal/apm/services/{serviceName}/profiling/timeline\" | \"GET /internal/apm/services/{serviceName}/profiling/statistics\" | \"GET /internal/apm/services/{serviceName}/alerts\" | \"GET /internal/apm/services/{serviceName}/infrastructure\" | \"GET /internal/apm/suggestions\" | \"GET /internal/apm/traces/{traceId}\" | \"GET /internal/apm/traces\" | \"GET /internal/apm/traces/{traceId}/root_transaction\" | \"GET /internal/apm/transactions/{transactionId}\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/latency\" | \"GET /internal/apm/services/{serviceName}/transactions/traces/samples\" | \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\" | \"GET /internal/apm/alerts/chart_preview/transaction_error_rate\" | \"GET /internal/apm/alerts/chart_preview/transaction_duration\" | \"GET /internal/apm/alerts/chart_preview/transaction_error_count\" | \"GET /api/apm/settings/agent-configuration\" | \"GET /api/apm/settings/agent-configuration/view\" | \"DELETE /api/apm/settings/agent-configuration\" | \"PUT /api/apm/settings/agent-configuration\" | \"POST /api/apm/settings/agent-configuration/search\" | \"GET /api/apm/settings/agent-configuration/services\" | \"GET /api/apm/settings/agent-configuration/environments\" | \"GET /api/apm/settings/agent-configuration/agent_name\" | \"GET /internal/apm/settings/anomaly-detection/jobs\" | \"POST /internal/apm/settings/anomaly-detection/jobs\" | \"GET /internal/apm/settings/anomaly-detection/environments\" | \"GET /internal/apm/settings/apm-index-settings\" | \"GET /internal/apm/settings/apm-indices\" | \"POST /internal/apm/settings/apm-indices/save\" | \"GET /internal/apm/settings/custom_links/transaction\" | \"GET /internal/apm/settings/custom_links\" | \"POST /internal/apm/settings/custom_links\" | \"PUT /internal/apm/settings/custom_links/{id}\" | \"DELETE /internal/apm/settings/custom_links/{id}\" | \"GET /api/apm/sourcemaps\" | \"POST /api/apm/sourcemaps\" | \"DELETE /api/apm/sourcemaps/{id}\" | \"GET /internal/apm/fleet/has_data\" | \"GET /internal/apm/fleet/agents\" | \"POST /api/apm/fleet/apm_server_schema\" | \"GET /internal/apm/fleet/apm_server_schema/unsupported\" | \"GET /internal/apm/fleet/migration_check\" | \"POST /internal/apm/fleet/cloud_apm_package_policy\" | \"GET /internal/apm/backends/top_backends\" | \"GET /internal/apm/backends/upstream_services\" | \"GET /internal/apm/backends/metadata\" | \"GET /internal/apm/backends/charts/latency\" | \"GET /internal/apm/backends/charts/throughput\" | \"GET /internal/apm/backends/charts/error_rate\" | \"GET /internal/apm/fallback_to_transactions\" | \"GET /internal/apm/has_data\" | \"GET /internal/apm/event_metadata/{processorEvent}/{id}\"" + "\"POST /internal/apm/data_view/static\" | \"GET /internal/apm/data_view/dynamic\" | \"GET /internal/apm/environments\" | \"GET /internal/apm/services/{serviceName}/errors\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}\" | \"GET /internal/apm/services/{serviceName}/errors/distribution\" | \"POST /internal/apm/latency/overall_distribution\" | \"GET /internal/apm/services/{serviceName}/metrics/charts\" | \"GET /internal/apm/observability_overview\" | \"GET /internal/apm/observability_overview/has_data\" | \"GET /internal/apm/ux/client-metrics\" | \"GET /internal/apm/ux/page-load-distribution\" | \"GET /internal/apm/ux/page-load-distribution/breakdown\" | \"GET /internal/apm/ux/page-view-trends\" | \"GET /internal/apm/ux/services\" | \"GET /internal/apm/ux/visitor-breakdown\" | \"GET /internal/apm/ux/web-core-vitals\" | \"GET /internal/apm/ux/long-task-metrics\" | \"GET /internal/apm/ux/url-search\" | \"GET /internal/apm/ux/js-errors\" | \"GET /api/apm/observability_overview/has_rum_data\" | \"GET /internal/apm/service-map\" | \"GET /internal/apm/service-map/service/{serviceName}\" | \"GET /internal/apm/service-map/backend\" | \"GET /internal/apm/services/{serviceName}/serviceNodes\" | \"GET /internal/apm/services\" | \"GET /internal/apm/services/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/metadata/details\" | \"GET /internal/apm/services/{serviceName}/metadata/icons\" | \"GET /internal/apm/services/{serviceName}/agent\" | \"GET /internal/apm/services/{serviceName}/transaction_types\" | \"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\" | \"GET /api/apm/services/{serviceName}/annotation/search\" | \"POST /api/apm/services/{serviceName}/annotation\" | \"GET /internal/apm/services/{serviceName}/error_groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/error_groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\" | \"GET /internal/apm/services/{serviceName}/throughput\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/dependencies\" | \"GET /internal/apm/services/{serviceName}/dependencies/breakdown\" | \"GET /internal/apm/services/{serviceName}/profiling/timeline\" | \"GET /internal/apm/services/{serviceName}/profiling/statistics\" | \"GET /internal/apm/services/{serviceName}/alerts\" | \"GET /internal/apm/services/{serviceName}/infrastructure\" | \"GET /internal/apm/suggestions\" | \"GET /internal/apm/traces/{traceId}\" | \"GET /internal/apm/traces\" | \"GET /internal/apm/traces/{traceId}/root_transaction\" | \"GET /internal/apm/transactions/{transactionId}\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/latency\" | \"GET /internal/apm/services/{serviceName}/transactions/traces/samples\" | \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\" | \"GET /internal/apm/alerts/chart_preview/transaction_error_rate\" | \"GET /internal/apm/alerts/chart_preview/transaction_duration\" | \"GET /internal/apm/alerts/chart_preview/transaction_error_count\" | \"GET /api/apm/settings/agent-configuration\" | \"GET /api/apm/settings/agent-configuration/view\" | \"DELETE /api/apm/settings/agent-configuration\" | \"PUT /api/apm/settings/agent-configuration\" | \"POST /api/apm/settings/agent-configuration/search\" | \"GET /api/apm/settings/agent-configuration/services\" | \"GET /api/apm/settings/agent-configuration/environments\" | \"GET /api/apm/settings/agent-configuration/agent_name\" | \"GET /internal/apm/settings/anomaly-detection/jobs\" | \"POST /internal/apm/settings/anomaly-detection/jobs\" | \"GET /internal/apm/settings/anomaly-detection/environments\" | \"GET /internal/apm/settings/apm-index-settings\" | \"GET /internal/apm/settings/apm-indices\" | \"POST /internal/apm/settings/apm-indices/save\" | \"GET /internal/apm/settings/custom_links/transaction\" | \"GET /internal/apm/settings/custom_links\" | \"POST /internal/apm/settings/custom_links\" | \"PUT /internal/apm/settings/custom_links/{id}\" | \"DELETE /internal/apm/settings/custom_links/{id}\" | \"GET /api/apm/sourcemaps\" | \"POST /api/apm/sourcemaps\" | \"DELETE /api/apm/sourcemaps/{id}\" | \"GET /internal/apm/fleet/has_data\" | \"GET /internal/apm/fleet/agents\" | \"POST /api/apm/fleet/apm_server_schema\" | \"GET /internal/apm/fleet/apm_server_schema/unsupported\" | \"GET /internal/apm/fleet/migration_check\" | \"POST /internal/apm/fleet/cloud_apm_package_policy\" | \"GET /internal/apm/backends/top_backends\" | \"GET /internal/apm/backends/upstream_services\" | \"GET /internal/apm/backends/metadata\" | \"GET /internal/apm/backends/charts/latency\" | \"GET /internal/apm/backends/charts/throughput\" | \"GET /internal/apm/backends/charts/error_rate\" | \"GET /internal/apm/fallback_to_transactions\" | \"GET /internal/apm/has_data\" | \"GET /internal/apm/event_metadata/{processorEvent}/{id}\"" ], "path": "x-pack/plugins/apm/server/routes/get_global_apm_server_route_repository.ts", "deprecated": false, @@ -1222,7 +1222,7 @@ "section": "def-server.APMRouteHandlerResources", "text": "APMRouteHandlerResources" }, - ", { serviceCount: number; transactionPerMinute: { value: undefined; timeseries: never[]; } | { value: number; timeseries: { x: number; y: number; }[]; }; }, ", + ", { serviceCount: number; transactionPerMinute: { value: undefined; timeseries: never[]; } | { value: number; timeseries: { x: number; y: number | null; }[]; }; }, ", "APMRouteCreateOptions", ">; } & { \"GET /internal/apm/observability_overview/has_data\": ", { @@ -1244,7 +1244,7 @@ "ApmIndicesConfig", "; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/rum/client-metrics\": ", + ">; } & { \"GET /internal/apm/ux/client-metrics\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1252,7 +1252,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/rum/client-metrics\", ", + "<\"GET /internal/apm/ux/client-metrics\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -1282,7 +1282,7 @@ }, ", { pageViews: { value: number; }; totalPageLoadDuration: { value: number; }; backEnd: { value: number; }; frontEnd: { value: number; }; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/rum-client/page-load-distribution\": ", + ">; } & { \"GET /internal/apm/ux/page-load-distribution\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1290,7 +1290,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/rum-client/page-load-distribution\", ", + "<\"GET /internal/apm/ux/page-load-distribution\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -1328,7 +1328,7 @@ }, ", { pageLoadDistribution: { pageLoadDistribution: { x: number; y: number; }[]; percentiles: Record | undefined; minDuration: number; maxDuration: number; } | null; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/rum-client/page-load-distribution/breakdown\": ", + ">; } & { \"GET /internal/apm/ux/page-load-distribution/breakdown\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1336,7 +1336,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/rum-client/page-load-distribution/breakdown\", ", + "<\"GET /internal/apm/ux/page-load-distribution/breakdown\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -1378,7 +1378,7 @@ }, ", { pageLoadDistBreakdown: { name: string; data: { x: number; y: number; }[]; }[] | undefined; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/rum-client/page-view-trends\": ", + ">; } & { \"GET /internal/apm/ux/page-view-trends\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1386,7 +1386,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/rum-client/page-view-trends\", ", + "<\"GET /internal/apm/ux/page-view-trends\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -1422,7 +1422,7 @@ }, ", { topItems: string[]; items: Record[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/rum-client/services\": ", + ">; } & { \"GET /internal/apm/ux/services\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1430,7 +1430,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/rum-client/services\", ", + "<\"GET /internal/apm/ux/services\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -1454,7 +1454,7 @@ }, ", { rumServices: string[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/rum-client/visitor-breakdown\": ", + ">; } & { \"GET /internal/apm/ux/visitor-breakdown\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1462,7 +1462,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/rum-client/visitor-breakdown\", ", + "<\"GET /internal/apm/ux/visitor-breakdown\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -1492,7 +1492,7 @@ }, ", { os: { count: number; name: string; }[]; browsers: { count: number; name: string; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/rum-client/web-core-vitals\": ", + ">; } & { \"GET /internal/apm/ux/web-core-vitals\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1500,7 +1500,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/rum-client/web-core-vitals\", ", + "<\"GET /internal/apm/ux/web-core-vitals\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -1530,7 +1530,7 @@ }, ", { coreVitalPages: number; cls: number | null; fid: number | null | undefined; lcp: number | null | undefined; tbt: number; fcp: number | null | undefined; lcpRanks: number[]; fidRanks: number[]; clsRanks: number[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/rum-client/long-task-metrics\": ", + ">; } & { \"GET /internal/apm/ux/long-task-metrics\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1538,7 +1538,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/rum-client/long-task-metrics\", ", + "<\"GET /internal/apm/ux/long-task-metrics\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -1568,7 +1568,7 @@ }, ", { noOfLongTasks: number; sumOfLongTasks: number; longestLongTask: number; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/rum-client/url-search\": ", + ">; } & { \"GET /internal/apm/ux/url-search\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1576,7 +1576,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/rum-client/url-search\", ", + "<\"GET /internal/apm/ux/url-search\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -1606,7 +1606,7 @@ }, ", { total: number; items: { url: string; count: number; pld: number; }[]; }, ", "APMRouteCreateOptions", - ">; } & { \"GET /api/apm/rum-client/js-errors\": ", + ">; } & { \"GET /internal/apm/ux/js-errors\": ", { "pluginId": "@kbn/server-route-repository", "scope": "server", @@ -1614,7 +1614,7 @@ "section": "def-server.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/apm/rum-client/js-errors\", ", + "<\"GET /internal/apm/ux/js-errors\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -2478,7 +2478,7 @@ "section": "def-server.APMRouteHandlerResources", "text": "APMRouteHandlerResources" }, - ", { currentPeriod: { x: number; y: number; }[]; previousPeriod: { x: number; y: number | null | undefined; }[]; }, ", + ", { currentPeriod: { x: number; y: number | null; }[]; previousPeriod: { x: number; y: number | null | undefined; }[]; }, ", "APMRouteCreateOptions", ">; } & { \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\": ", { @@ -3456,7 +3456,7 @@ "section": "def-server.APMRouteHandlerResources", "text": "APMRouteHandlerResources" }, - ", { noHits: boolean; traceSamples: { transactionId: string; traceId: string; }[]; }, ", + ", { traceSamples: { transactionId: string; traceId: string; }[]; }, ", "APMRouteCreateOptions", ">; } & { \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\": ", { @@ -3580,9 +3580,9 @@ "section": "def-server.APMRouteHandlerResources", "text": "APMRouteHandlerResources" }, - ", { currentPeriod: { noHits: boolean; transactionErrorRate: ", + ", { currentPeriod: { timeseries: ", "Coordinate", - "[]; average: number | null; }; previousPeriod: { transactionErrorRate: { x: number; y: number | null | undefined; }[]; noHits: boolean; average: number | null; }; }, ", + "[]; average: number | null; }; previousPeriod: { timeseries: { x: number; y: number | null | undefined; }[]; average: number | null; }; }, ", "APMRouteCreateOptions", ">; } & { \"GET /internal/apm/alerts/chart_preview/transaction_error_rate\": ", { @@ -4832,7 +4832,7 @@ "section": "def-server.APMRouteHandlerResources", "text": "APMRouteHandlerResources" }, - ", { currentTimeseries: { x: number; y: number; }[]; comparisonTimeseries: { x: number; y: number; }[] | null; }, ", + ", { currentTimeseries: { x: number; y: number | null; }[]; comparisonTimeseries: { x: number; y: number | null; }[] | null; }, ", "APMRouteCreateOptions", ">; } & { \"GET /internal/apm/backends/charts/error_rate\": ", { diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/Metrics.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/Metrics.tsx index 3a9100a0712aa..ded242e2ce558 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/Metrics.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/Metrics.tsx @@ -55,7 +55,7 @@ export function Metrics() { (callApmApi) => { if (uxQuery) { return callApmApi({ - endpoint: 'GET /api/apm/rum/client-metrics', + endpoint: 'GET /internal/apm/ux/client-metrics', params: { query: { ...uxQuery, diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpactfulMetrics/JSErrors.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpactfulMetrics/JSErrors.tsx index b8bdc36ed4e0d..7f481d1c14dc2 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpactfulMetrics/JSErrors.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpactfulMetrics/JSErrors.tsx @@ -41,7 +41,7 @@ export function JSErrors() { (callApmApi) => { if (start && end && serviceName) { return callApmApi({ - endpoint: 'GET /api/apm/rum-client/js-errors', + endpoint: 'GET /internal/apm/ux/js-errors', params: { query: { start, diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index f75d0fd093b5a..6798fbe90e4de 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -51,7 +51,7 @@ export function PageLoadDistribution() { (callApmApi) => { if (start && end && serviceName) { return callApmApi({ - endpoint: 'GET /api/apm/rum-client/page-load-distribution', + endpoint: 'GET /internal/apm/ux/page-load-distribution', params: { query: { start, diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts index 0cfa293c87844..ee3acac73211f 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts @@ -24,7 +24,7 @@ export const useBreakdowns = ({ percentileRange, field, value }: Props) => { (callApmApi) => { if (start && end && field && value) { return callApmApi({ - endpoint: 'GET /api/apm/rum-client/page-load-distribution/breakdown', + endpoint: 'GET /internal/apm/ux/page-load-distribution/breakdown', params: { query: { start, diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx index 581260f5931e7..16605a83505ff 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx @@ -39,7 +39,7 @@ export function PageViewsTrend() { (callApmApi) => { if (start && end && serviceName) { return callApmApi({ - endpoint: 'GET /api/apm/rum-client/page-view-trends', + endpoint: 'GET /internal/apm/ux/page-view-trends', params: { query: { start, diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Panels/WebApplicationSelect.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Panels/WebApplicationSelect.tsx index 5b1cca0ec44fa..ecba89b2651ac 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Panels/WebApplicationSelect.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Panels/WebApplicationSelect.tsx @@ -20,7 +20,7 @@ export function WebApplicationSelect() { (callApmApi) => { if (start && end) { return callApmApi({ - endpoint: 'GET /api/apm/rum-client/services', + endpoint: 'GET /internal/apm/ux/services', params: { query: { start, diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/use_url_search.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/use_url_search.tsx index 7b6b093c70367..8228ab4c6e83e 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/use_url_search.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/use_url_search.tsx @@ -38,7 +38,7 @@ export const useUrlSearch = ({ popoverIsOpen, query }: Props) => { (callApmApi) => { if (uxQuery && popoverIsOpen) { return callApmApi({ - endpoint: 'GET /api/apm/rum-client/url-search', + endpoint: 'GET /internal/apm/ux/url-search', params: { query: { ...uxQuery, diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/KeyUXMetrics.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/KeyUXMetrics.tsx index b8766e8b5ce67..4eaf0dccc3225 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/KeyUXMetrics.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/KeyUXMetrics.tsx @@ -56,7 +56,7 @@ export function KeyUXMetrics({ data, loading }: Props) { (callApmApi) => { if (uxQuery) { return callApmApi({ - endpoint: 'GET /api/apm/rum-client/long-task-metrics', + endpoint: 'GET /internal/apm/ux/long-task-metrics', params: { query: { ...uxQuery, diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/index.tsx index 673f045ecfb97..ab6843f94ee43 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/index.tsx @@ -34,7 +34,7 @@ export function UXMetrics() { (callApmApi) => { if (uxQuery) { return callApmApi({ - endpoint: 'GET /api/apm/rum-client/web-core-vitals', + endpoint: 'GET /internal/apm/ux/web-core-vitals', params: { query: uxQuery, }, diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdown/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdown/index.tsx index f044890a9b649..7a19690a4582e 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdown/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdown/index.tsx @@ -23,7 +23,7 @@ export function VisitorBreakdown() { if (start && end && serviceName) { return callApmApi({ - endpoint: 'GET /api/apm/rum-client/visitor-breakdown', + endpoint: 'GET /internal/apm/ux/visitor-breakdown', params: { query: { start, diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ux_overview_fetchers.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/ux_overview_fetchers.ts index 34dd2d53daf8e..61310a5c5ad2c 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ux_overview_fetchers.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ux_overview_fetchers.ts @@ -21,7 +21,7 @@ export const fetchUxOverviewDate = async ({ serviceName, }: FetchDataParams): Promise => { const data = await callApmApi({ - endpoint: 'GET /api/apm/rum-client/web-core-vitals', + endpoint: 'GET /internal/apm/ux/web-core-vitals', signal: null, params: { query: { diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts index 45f8d9f6149ff..e84a281a7ce1b 100644 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -65,7 +65,7 @@ const uxQueryRt = t.intersection([ ]); const rumClientMetricsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/rum/client-metrics', + endpoint: 'GET /internal/apm/ux/client-metrics', params: t.type({ query: uxQueryRt, }), @@ -88,7 +88,7 @@ const rumClientMetricsRoute = createApmServerRoute({ }); const rumPageLoadDistributionRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/rum-client/page-load-distribution', + endpoint: 'GET /internal/apm/ux/page-load-distribution', params: t.type({ query: t.intersection([uxQueryRt, percentileRangeRt]), }), @@ -114,7 +114,7 @@ const rumPageLoadDistributionRoute = createApmServerRoute({ }); const rumPageLoadDistBreakdownRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/rum-client/page-load-distribution/breakdown', + endpoint: 'GET /internal/apm/ux/page-load-distribution/breakdown', params: t.type({ query: t.intersection([ uxQueryRt, @@ -145,7 +145,7 @@ const rumPageLoadDistBreakdownRoute = createApmServerRoute({ }); const rumPageViewsTrendRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/rum-client/page-view-trends', + endpoint: 'GET /internal/apm/ux/page-view-trends', params: t.type({ query: t.intersection([uxQueryRt, t.partial({ breakdowns: t.string })]), }), @@ -168,7 +168,7 @@ const rumPageViewsTrendRoute = createApmServerRoute({ }); const rumServicesRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/rum-client/services', + endpoint: 'GET /internal/apm/ux/services', params: t.type({ query: t.intersection([uiFiltersRt, rangeRt]), }), @@ -184,7 +184,7 @@ const rumServicesRoute = createApmServerRoute({ }); const rumVisitorsBreakdownRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/rum-client/visitor-breakdown', + endpoint: 'GET /internal/apm/ux/visitor-breakdown', params: t.type({ query: uxQueryRt, }), @@ -206,7 +206,7 @@ const rumVisitorsBreakdownRoute = createApmServerRoute({ }); const rumWebCoreVitals = createApmServerRoute({ - endpoint: 'GET /api/apm/rum-client/web-core-vitals', + endpoint: 'GET /internal/apm/ux/web-core-vitals', params: t.type({ query: uxQueryRt, }), @@ -229,7 +229,7 @@ const rumWebCoreVitals = createApmServerRoute({ }); const rumLongTaskMetrics = createApmServerRoute({ - endpoint: 'GET /api/apm/rum-client/long-task-metrics', + endpoint: 'GET /internal/apm/ux/long-task-metrics', params: t.type({ query: uxQueryRt, }), @@ -252,7 +252,7 @@ const rumLongTaskMetrics = createApmServerRoute({ }); const rumUrlSearch = createApmServerRoute({ - endpoint: 'GET /api/apm/rum-client/url-search', + endpoint: 'GET /internal/apm/ux/url-search', params: t.type({ query: uxQueryRt, }), @@ -275,7 +275,7 @@ const rumUrlSearch = createApmServerRoute({ }); const rumJSErrors = createApmServerRoute({ - endpoint: 'GET /api/apm/rum-client/js-errors', + endpoint: 'GET /internal/apm/ux/js-errors', params: t.type({ query: t.intersection([ uiFiltersRt, diff --git a/x-pack/plugins/uptime/common/constants/rest_api.ts b/x-pack/plugins/uptime/common/constants/rest_api.ts index 52b0620586eb4..26b2c7aad20ac 100644 --- a/x-pack/plugins/uptime/common/constants/rest_api.ts +++ b/x-pack/plugins/uptime/common/constants/rest_api.ts @@ -6,16 +6,23 @@ */ export enum API_URLS { - INDEX_STATUS = '/api/uptime/index_status', - MONITOR_LIST = `/api/uptime/monitor/list`, - MONITOR_LOCATIONS = `/api/uptime/monitor/locations`, - MONITOR_DURATION = `/api/uptime/monitor/duration`, - MONITOR_DETAILS = `/api/uptime/monitor/details`, - MONITOR_STATUS = `/api/uptime/monitor/status`, - PINGS = '/api/uptime/pings', - PING_HISTOGRAM = `/api/uptime/ping/histogram`, - SNAPSHOT_COUNT = `/api/uptime/snapshot/count`, - LOG_PAGE_VIEW = `/api/uptime/log_page_view`, + DYNAMIC_SETTINGS = `/internal/uptime/dynamic_settings`, + INDEX_STATUS = '/internal/uptime/index_status', + MONITOR_LIST = `/internal/uptime/monitor/list`, + MONITOR_LOCATIONS = `/internal/uptime/monitor/locations`, + MONITOR_DURATION = `/internal/uptime/monitor/duration`, + MONITOR_DETAILS = `/internal/uptime/monitor/details`, + MONITOR_STATUS = `/internal/uptime/monitor/status`, + NETWORK_EVENTS = `/internal/uptime/network_events`, + PINGS = '/internal/uptime/pings', + PING_HISTOGRAM = `/internal/uptime/ping/histogram`, + SNAPSHOT_COUNT = `/internal/uptime/snapshot/count`, + SYNTHETICS_SUCCESSFUL_STEP = `/internal/uptime/synthetics/step/success`, + JOURNEY_CREATE = `/internal/uptime/journey/{checkGroup}`, + JOURNEY_FAILED_STEPS = `/internal/uptime/journeys/failed_steps`, + JOURNEY_SCREENSHOT = `/internal/uptime/journey/screenshot/{checkGroup}/{stepIndex}`, + JOURNEY_SCREENSHOT_BLOCKS = `/internal/uptime/journey/screenshot/block`, + LOG_PAGE_VIEW = `/internal/uptime/log_page_view`, ML_MODULE_JOBS = `/api/ml/modules/jobs_exist/`, ML_SETUP_MODULE = '/api/ml/modules/setup/', diff --git a/x-pack/plugins/uptime/public/components/monitor/ping_list/columns/ping_timestamp/ping_timestamp.tsx b/x-pack/plugins/uptime/public/components/monitor/ping_list/columns/ping_timestamp/ping_timestamp.tsx index 425f35b067026..ed7fb34b92f07 100644 --- a/x-pack/plugins/uptime/public/components/monitor/ping_list/columns/ping_timestamp/ping_timestamp.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/ping_list/columns/ping_timestamp/ping_timestamp.tsx @@ -48,7 +48,7 @@ export const PingTimestamp = ({ label, checkGroup, initialStepNo = 1 }: Props) = const { basePath } = useContext(UptimeSettingsContext); - const imgPath = `${basePath}/api/uptime/journey/screenshot/${checkGroup}/${stepNumber}`; + const imgPath = `${basePath}/internal/uptime/journey/screenshot/${checkGroup}/${stepNumber}`; const intersection = useIntersection(intersectionRef, { root: null, diff --git a/x-pack/plugins/uptime/public/components/synthetics/step_screenshot_display.tsx b/x-pack/plugins/uptime/public/components/synthetics/step_screenshot_display.tsx index c20445cf72c38..2a83fc3115ce3 100644 --- a/x-pack/plugins/uptime/public/components/synthetics/step_screenshot_display.tsx +++ b/x-pack/plugins/uptime/public/components/synthetics/step_screenshot_display.tsx @@ -123,7 +123,7 @@ export const StepScreenshotDisplay: FC = ({ } }, [hasIntersected, isIntersecting, setHasIntersected]); - const imgSrc = basePath + `/api/uptime/journey/screenshot/${checkGroup}/${stepIndex}`; + const imgSrc = basePath + `/internal/uptime/journey/screenshot/${checkGroup}/${stepIndex}`; // When loading a legacy screenshot, set `url` to full-size screenshot path. // Otherwise, we first need to composite the image. diff --git a/x-pack/plugins/uptime/public/state/api/dynamic_settings.ts b/x-pack/plugins/uptime/public/state/api/dynamic_settings.ts index 3aa300e69e3fe..a7bacfbba3462 100644 --- a/x-pack/plugins/uptime/public/state/api/dynamic_settings.ts +++ b/x-pack/plugins/uptime/public/state/api/dynamic_settings.ts @@ -12,8 +12,9 @@ import { DynamicSettingsSaveType, } from '../../../common/runtime_types'; import { apiService } from './utils'; +import { API_URLS } from '../../../common/constants'; -const apiPath = '/api/uptime/dynamic_settings'; +const apiPath = API_URLS.DYNAMIC_SETTINGS; interface SaveApiRequest { settings: DynamicSettings; diff --git a/x-pack/plugins/uptime/public/state/api/journey.ts b/x-pack/plugins/uptime/public/state/api/journey.ts index 05d4a9e356919..258d00c5d278e 100644 --- a/x-pack/plugins/uptime/public/state/api/journey.ts +++ b/x-pack/plugins/uptime/public/state/api/journey.ts @@ -18,9 +18,10 @@ import { SyntheticsJourneyApiResponse, SyntheticsJourneyApiResponseType, } from '../../../common/runtime_types/ping/synthetics'; +import { API_URLS } from '../../../common/constants'; export async function fetchScreenshotBlockSet(params: string[]): Promise { - return apiService.post('/api/uptime/journey/screenshot/block', { + return apiService.post(API_URLS.JOURNEY_SCREENSHOT_BLOCKS, { hashes: params, }); } @@ -29,7 +30,7 @@ export async function fetchJourneySteps( params: FetchJourneyStepsParams ): Promise { return apiService.get( - `/api/uptime/journey/${params.checkGroup}`, + `/internal/uptime/journey/${params.checkGroup}`, { syntheticEventTypes: params.syntheticEventTypes }, SyntheticsJourneyApiResponseType ); @@ -40,11 +41,7 @@ export async function fetchJourneysFailedSteps({ }: { checkGroups: string[]; }): Promise { - return apiService.get( - `/api/uptime/journeys/failed_steps`, - { checkGroups }, - FailedStepsApiResponseType - ); + return apiService.get(API_URLS.JOURNEY_FAILED_STEPS, { checkGroups }, FailedStepsApiResponseType); } export async function fetchLastSuccessfulStep({ @@ -59,7 +56,7 @@ export async function fetchLastSuccessfulStep({ location?: string; }): Promise { return await apiService.get( - `/api/uptime/synthetics/step/success/`, + API_URLS.SYNTHETICS_SUCCESSFUL_STEP, { monitorId, timestamp, diff --git a/x-pack/plugins/uptime/public/state/api/network_events.ts b/x-pack/plugins/uptime/public/state/api/network_events.ts index ea3bb6e5183e4..d9b3d518444a3 100644 --- a/x-pack/plugins/uptime/public/state/api/network_events.ts +++ b/x-pack/plugins/uptime/public/state/api/network_events.ts @@ -11,12 +11,13 @@ import { SyntheticsNetworkEventsApiResponse, SyntheticsNetworkEventsApiResponseType, } from '../../../common/runtime_types'; +import { API_URLS } from '../../../common/constants'; export async function fetchNetworkEvents( params: FetchNetworkEventsParams ): Promise { return (await apiService.get( - `/api/uptime/network_events`, + API_URLS.NETWORK_EVENTS, { checkGroup: params.checkGroup, stepIndex: params.stepIndex, diff --git a/x-pack/plugins/uptime/public/state/api/snapshot.test.ts b/x-pack/plugins/uptime/public/state/api/snapshot.test.ts index 38be97d74844f..01177eceb4720 100644 --- a/x-pack/plugins/uptime/public/state/api/snapshot.test.ts +++ b/x-pack/plugins/uptime/public/state/api/snapshot.test.ts @@ -8,6 +8,7 @@ import { HttpFetchError } from 'src/core/public'; import { fetchSnapshotCount } from './snapshot'; import { apiService } from './utils'; +import { API_URLS } from '../../../common/constants'; describe('snapshot API', () => { let fetchMock: jest.SpyInstance>; @@ -36,7 +37,7 @@ describe('snapshot API', () => { }); expect(fetchMock).toHaveBeenCalledWith({ asResponse: false, - path: '/api/uptime/snapshot/count', + path: API_URLS.SNAPSHOT_COUNT, query: { dateRangeEnd: 'now', dateRangeStart: 'now-15m', diff --git a/x-pack/plugins/uptime/server/rest_api/dynamic_settings.ts b/x-pack/plugins/uptime/server/rest_api/dynamic_settings.ts index 637ac72e12ee5..5d9947e23cf44 100644 --- a/x-pack/plugins/uptime/server/rest_api/dynamic_settings.ts +++ b/x-pack/plugins/uptime/server/rest_api/dynamic_settings.ts @@ -16,10 +16,11 @@ import { VALUE_MUST_BE_GREATER_THAN_ZERO, VALUE_MUST_BE_AN_INTEGER, } from '../../common/translations'; +import { API_URLS } from '../../common/constants'; export const createGetDynamicSettingsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', - path: '/api/uptime/dynamic_settings', + path: API_URLS.DYNAMIC_SETTINGS, validate: false, handler: async ({ savedObjectsClient }): Promise => { return savedObjectsAdapter.getUptimeDynamicSettings(savedObjectsClient); @@ -47,7 +48,7 @@ export const validateCertsValues = ( export const createPostDynamicSettingsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'POST', - path: '/api/uptime/dynamic_settings', + path: API_URLS.DYNAMIC_SETTINGS, validate: { body: schema.object({ heartbeatIndices: schema.string(), diff --git a/x-pack/plugins/uptime/server/rest_api/network_events/get_network_events.ts b/x-pack/plugins/uptime/server/rest_api/network_events/get_network_events.ts index 21ca946e574d1..0afe21413d4fb 100644 --- a/x-pack/plugins/uptime/server/rest_api/network_events/get_network_events.ts +++ b/x-pack/plugins/uptime/server/rest_api/network_events/get_network_events.ts @@ -8,10 +8,11 @@ import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; +import { API_URLS } from '../../../common/constants'; export const createNetworkEventsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', - path: '/api/uptime/network_events', + path: API_URLS.NETWORK_EVENTS, validate: { query: schema.object({ checkGroup: schema.string(), diff --git a/x-pack/plugins/uptime/server/rest_api/pings/journey_screenshot_blocks.ts b/x-pack/plugins/uptime/server/rest_api/pings/journey_screenshot_blocks.ts index 4b06a13d29f4e..95c30b5f73689 100644 --- a/x-pack/plugins/uptime/server/rest_api/pings/journey_screenshot_blocks.ts +++ b/x-pack/plugins/uptime/server/rest_api/pings/journey_screenshot_blocks.ts @@ -10,6 +10,7 @@ import { isRight } from 'fp-ts/lib/Either'; import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; +import { API_URLS } from '../../../common/constants'; function isStringArray(data: unknown): data is string[] { return isRight(t.array(t.string).decode(data)); @@ -17,7 +18,7 @@ function isStringArray(data: unknown): data is string[] { export const createJourneyScreenshotBlocksRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'POST', - path: '/api/uptime/journey/screenshot/block', + path: API_URLS.JOURNEY_SCREENSHOT_BLOCKS, validate: { body: schema.object({ hashes: schema.arrayOf(schema.string()), diff --git a/x-pack/plugins/uptime/server/rest_api/pings/journey_screenshots.ts b/x-pack/plugins/uptime/server/rest_api/pings/journey_screenshots.ts index 3e71051816d30..146460295f444 100644 --- a/x-pack/plugins/uptime/server/rest_api/pings/journey_screenshots.ts +++ b/x-pack/plugins/uptime/server/rest_api/pings/journey_screenshots.ts @@ -10,6 +10,7 @@ import { isRefResult, isFullScreenshot } from '../../../common/runtime_types/pin import { UMServerLibs } from '../../lib/lib'; import { ScreenshotReturnTypesUnion } from '../../lib/requests/get_journey_screenshot'; import { UMRestApiRouteFactory } from '../types'; +import { API_URLS } from '../../../common/constants'; function getSharedHeaders(stepName: string, totalSteps: number) { return { @@ -21,7 +22,7 @@ function getSharedHeaders(stepName: string, totalSteps: number) { export const createJourneyScreenshotRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', - path: '/api/uptime/journey/screenshot/{checkGroup}/{stepIndex}', + path: API_URLS.JOURNEY_SCREENSHOT, validate: { params: schema.object({ checkGroup: schema.string(), diff --git a/x-pack/plugins/uptime/server/rest_api/pings/journeys.ts b/x-pack/plugins/uptime/server/rest_api/pings/journeys.ts index 7c3dcdfbe845c..bfc5a52e3e01f 100644 --- a/x-pack/plugins/uptime/server/rest_api/pings/journeys.ts +++ b/x-pack/plugins/uptime/server/rest_api/pings/journeys.ts @@ -8,10 +8,11 @@ import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; +import { API_URLS } from '../../../common/constants'; export const createJourneyRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', - path: '/api/uptime/journey/{checkGroup}', + path: API_URLS.JOURNEY_CREATE, validate: { params: schema.object({ checkGroup: schema.string(), @@ -54,7 +55,7 @@ export const createJourneyRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => export const createJourneyFailedStepsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', - path: '/api/uptime/journeys/failed_steps', + path: API_URLS.JOURNEY_FAILED_STEPS, validate: { query: schema.object({ checkGroups: schema.arrayOf(schema.string()), diff --git a/x-pack/plugins/uptime/server/rest_api/synthetics/last_successful_step.ts b/x-pack/plugins/uptime/server/rest_api/synthetics/last_successful_step.ts index 81539459172cc..99695bbce09a0 100644 --- a/x-pack/plugins/uptime/server/rest_api/synthetics/last_successful_step.ts +++ b/x-pack/plugins/uptime/server/rest_api/synthetics/last_successful_step.ts @@ -13,10 +13,11 @@ import { } from '../../../common/runtime_types/ping/synthetics'; import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; +import { API_URLS } from '../../../common/constants'; export const createLastSuccessfulStepRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', - path: '/api/uptime/synthetics/step/success/', + path: API_URLS.SYNTHETICS_SUCCESSFUL_STEP, validate: { query: schema.object({ monitorId: schema.string(), diff --git a/x-pack/test/api_integration/apis/uptime/get_all_pings.ts b/x-pack/test/api_integration/apis/uptime/get_all_pings.ts index cf52d72823095..2658afd0d90d2 100644 --- a/x-pack/test/api_integration/apis/uptime/get_all_pings.ts +++ b/x-pack/test/api_integration/apis/uptime/get_all_pings.ts @@ -9,6 +9,7 @@ import moment from 'moment'; import expect from '@kbn/expect'; import { PINGS_DATE_RANGE_START, PINGS_DATE_RANGE_END } from './constants'; import { FtrProviderContext } from '../../ftr_provider_context'; +import { API_URLS } from '../../../../plugins/uptime/common/constants'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); @@ -22,9 +23,12 @@ export default function ({ getService }: FtrProviderContext) { it('should get all pings stored in index', async () => { const { body: apiResponse } = await supertest - .get( - `/api/uptime/pings?sort=desc&from=${PINGS_DATE_RANGE_START}&to=${PINGS_DATE_RANGE_END}` - ) + .get(API_URLS.PINGS) + .query({ + sort: 'desc', + from: PINGS_DATE_RANGE_START, + to: PINGS_DATE_RANGE_END, + }) .expect(200); expect(apiResponse.total).to.be(2); @@ -34,7 +38,12 @@ export default function ({ getService }: FtrProviderContext) { it('should sort pings according to timestamp', async () => { const { body: apiResponse } = await supertest - .get(`/api/uptime/pings?sort=asc&from=${PINGS_DATE_RANGE_START}&to=${PINGS_DATE_RANGE_END}`) + .get(API_URLS.PINGS) + .query({ + sort: 'asc', + from: PINGS_DATE_RANGE_START, + to: PINGS_DATE_RANGE_END, + }) .expect(200); expect(apiResponse.total).to.be(2); @@ -45,9 +54,13 @@ export default function ({ getService }: FtrProviderContext) { it('should return results of n length', async () => { const { body: apiResponse } = await supertest - .get( - `/api/uptime/pings?sort=desc&size=1&from=${PINGS_DATE_RANGE_START}&to=${PINGS_DATE_RANGE_END}` - ) + .get(API_URLS.PINGS) + .query({ + sort: 'desc', + size: 1, + from: PINGS_DATE_RANGE_START, + to: PINGS_DATE_RANGE_END, + }) .expect(200); expect(apiResponse.total).to.be(2); @@ -59,7 +72,8 @@ export default function ({ getService }: FtrProviderContext) { const from = moment('2002-01-01').valueOf(); const to = moment('2002-01-02').valueOf(); const { body: apiResponse } = await supertest - .get(`/api/uptime/pings?from=${from}&to=${to}`) + .get(API_URLS.PINGS) + .query({ from, to }) .expect(200); expect(apiResponse.total).to.be(0); diff --git a/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts b/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts index d5cf2078e377b..84e01ecef63d6 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts @@ -12,13 +12,16 @@ import { DynamicSettingsType, DynamicSettings, } from '../../../../../plugins/uptime/common/runtime_types'; -import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../plugins/uptime/common/constants'; +import { + DYNAMIC_SETTINGS_DEFAULTS, + API_URLS, +} from '../../../../../plugins/uptime/common/constants'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); describe('dynamic settings', () => { it('returns the defaults when no user settings have been saved', async () => { - const apiResponse = await supertest.get(`/api/uptime/dynamic_settings`); + const apiResponse = await supertest.get(API_URLS.DYNAMIC_SETTINGS); expect(apiResponse.body).to.eql(DYNAMIC_SETTINGS_DEFAULTS); expect(isRight(DynamicSettingsType.decode(apiResponse.body))).to.be.ok(); }); @@ -31,14 +34,14 @@ export default function ({ getService }: FtrProviderContext) { defaultConnectors: [], }; const postResponse = await supertest - .post(`/api/uptime/dynamic_settings`) + .post(API_URLS.DYNAMIC_SETTINGS) .set('kbn-xsrf', 'true') .send(newSettings); expect(postResponse.body).to.eql({ success: true }); expect(postResponse.status).to.eql(200); - const getResponse = await supertest.get(`/api/uptime/dynamic_settings`); + const getResponse = await supertest.get(API_URLS.DYNAMIC_SETTINGS); expect(getResponse.body).to.eql(newSettings); expect(isRight(DynamicSettingsType.decode(getResponse.body))).to.be.ok(); }); diff --git a/x-pack/test/api_integration/apis/uptime/rest/filters.ts b/x-pack/test/api_integration/apis/uptime/rest/filters.ts deleted file mode 100644 index 5603d142cdb61..0000000000000 --- a/x-pack/test/api_integration/apis/uptime/rest/filters.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { expectFixtureEql } from './helper/expect_fixture_eql'; -import { FtrProviderContext } from '../../../ftr_provider_context'; - -const getApiPath = (dateRangeStart: string, dateRangeEnd: string, filters?: string) => - `/api/uptime/filters?dateRangeStart=${dateRangeStart}&dateRangeEnd=${dateRangeEnd}${ - filters ? `&filters=${filters}` : '' - }`; - -export default function ({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); - - describe('filter group endpoint', () => { - const dateRangeStart = '2019-01-28T17:40:08.078Z'; - const dateRangeEnd = '2025-01-28T19:00:16.078Z'; - - it('returns expected filters', async () => { - const resp = await supertest.get(getApiPath(dateRangeStart, dateRangeEnd)); - expectFixtureEql(resp.body, 'filters'); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/uptime/rest/monitor_duration.ts b/x-pack/test/api_integration/apis/uptime/rest/monitor_duration.ts index 92c5174c7263d..4fa0837e2e812 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/monitor_duration.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/monitor_duration.ts @@ -7,6 +7,7 @@ import { expectFixtureEql } from './helper/expect_fixture_eql'; import { FtrProviderContext } from '../../../ftr_provider_context'; +import { API_URLS } from '../../../../../plugins/uptime/common/constants'; export default function ({ getService }: FtrProviderContext) { describe('monitor duration query', () => { @@ -18,9 +19,11 @@ export default function ({ getService }: FtrProviderContext) { const monitorId = '0002-up'; - const apiResponse = await supertest.get( - `/api/uptime/monitor/duration?monitorId=${monitorId}&dateStart=${dateStart}&dateEnd=${dateEnd}` - ); + const apiResponse = await supertest.get(API_URLS.MONITOR_DURATION).query({ + monitorId, + dateStart, + dateEnd, + }); const data = apiResponse.body; expectFixtureEql(data, 'monitor_charts'); }); @@ -31,9 +34,11 @@ export default function ({ getService }: FtrProviderContext) { const monitorId = '0002-up'; - const apiResponse = await supertest.get( - `/api/uptime/monitor/duration?monitorId=${monitorId}&dateStart=${dateStart}&dateEnd=${dateEnd}` - ); + const apiResponse = await supertest.get(API_URLS.MONITOR_DURATION).query({ + monitorId, + dateStart, + dateEnd, + }); const data = apiResponse.body; expectFixtureEql(data, 'monitor_charts_empty_sets'); diff --git a/x-pack/test/api_integration/apis/uptime/rest/monitor_latest_status.ts b/x-pack/test/api_integration/apis/uptime/rest/monitor_latest_status.ts index 69b1bd0324ee6..036d3ad856f57 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/monitor_latest_status.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/monitor_latest_status.ts @@ -7,6 +7,7 @@ import { expectFixtureEql } from './helper/expect_fixture_eql'; import { FtrProviderContext } from '../../../ftr_provider_context'; +import { API_URLS } from '../../../../../plugins/uptime/common/constants'; export default function ({ getService }: FtrProviderContext) { describe('get monitor latest status API', () => { @@ -17,9 +18,11 @@ export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); it('returns the status for only the given monitor', async () => { - const apiResponse = await supertest.get( - `/api/uptime/monitor/status?monitorId=${monitorId}&dateStart=${dateStart}&dateEnd=${dateEnd}` - ); + const apiResponse = await supertest.get(API_URLS.MONITOR_STATUS).query({ + monitorId, + dateStart, + dateEnd, + }); expectFixtureEql(apiResponse.body, 'monitor_latest_status'); }); }); diff --git a/x-pack/test/api_integration/apis/uptime/rest/ping_histogram.ts b/x-pack/test/api_integration/apis/uptime/rest/ping_histogram.ts index 0d69b083d8f23..fcc0873be9a76 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/ping_histogram.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/ping_histogram.ts @@ -7,6 +7,7 @@ import { expectFixtureEql } from './helper/expect_fixture_eql'; import { FtrProviderContext } from '../../../ftr_provider_context'; +import { API_URLS } from '../../../../../plugins/uptime/common/constants'; export default function ({ getService }: FtrProviderContext) { describe('pingHistogram', () => { @@ -16,9 +17,10 @@ export default function ({ getService }: FtrProviderContext) { const dateStart = '2019-09-11T03:31:04.380Z'; const dateEnd = '2019-09-11T03:40:34.410Z'; - const apiResponse = await supertest.get( - `/api/uptime/ping/histogram?dateStart=${dateStart}&dateEnd=${dateEnd}` - ); + const apiResponse = await supertest.get(API_URLS.PING_HISTOGRAM).query({ + dateStart, + dateEnd, + }); const data = apiResponse.body; expectFixtureEql(data, 'ping_histogram'); @@ -29,9 +31,11 @@ export default function ({ getService }: FtrProviderContext) { const dateEnd = '2019-09-11T03:40:34.410Z'; const monitorId = '0002-up'; - const apiResponse = await supertest.get( - `/api/uptime/ping/histogram?monitorId=${monitorId}&dateStart=${dateStart}&dateEnd=${dateEnd}` - ); + const apiResponse = await supertest.get(API_URLS.PING_HISTOGRAM).query({ + monitorId, + dateStart, + dateEnd, + }); const data = apiResponse.body; expectFixtureEql(data, 'ping_histogram_by_id'); @@ -43,9 +47,11 @@ export default function ({ getService }: FtrProviderContext) { const filters = '{"bool":{"must":[{"match":{"monitor.status":{"query":"up","operator":"and"}}}]}}'; - const apiResponse = await supertest.get( - `/api/uptime/ping/histogram?dateStart=${dateStart}&dateEnd=${dateEnd}&filters=${filters}` - ); + const apiResponse = await supertest.get(API_URLS.PING_HISTOGRAM).query({ + dateStart, + dateEnd, + filters, + }); const data = apiResponse.body; expectFixtureEql(data, 'ping_histogram_by_filter'); diff --git a/x-pack/test/api_integration/apis/uptime/rest/ping_list.ts b/x-pack/test/api_integration/apis/uptime/rest/ping_list.ts index 860aae81703f4..7a0367728eed7 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/ping_list.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/ping_list.ts @@ -10,6 +10,7 @@ import { isLeft } from 'fp-ts/lib/Either'; import { PathReporter } from 'io-ts/lib/PathReporter'; import { PingsResponseType } from '../../../../../plugins/uptime/common/runtime_types'; import { FtrProviderContext } from '../../../ftr_provider_context'; +import { API_URLS } from '../../../../../plugins/uptime/common/constants'; function decodePingsResponseData(response: any) { const decoded = PingsResponseType.decode(response); @@ -33,7 +34,11 @@ export default function ({ getService }: FtrProviderContext) { const from = '2019-01-28T17:40:08.078Z'; const to = '2025-01-28T19:00:16.078Z'; - const apiResponse = await supertest.get(`/api/uptime/pings?from=${from}&to=${to}&size=10`); + const apiResponse = await supertest.get(API_URLS.PINGS).query({ + from, + to, + size: 10, + }); const { total, pings } = decodePingsResponseData(apiResponse.body); @@ -58,9 +63,11 @@ export default function ({ getService }: FtrProviderContext) { const to = '2025-01-28T19:00:16.078Z'; const size = 50; - const apiResponse = await supertest.get( - `/api/uptime/pings?from=${from}&to=${to}&size=${size}` - ); + const apiResponse = await supertest.get(API_URLS.PINGS).query({ + from, + to, + size, + }); const { total, pings } = decodePingsResponseData(apiResponse.body); @@ -126,9 +133,12 @@ export default function ({ getService }: FtrProviderContext) { const monitorId = '0001-up'; const size = 15; - const apiResponse = await supertest.get( - `/api/uptime/pings?from=${from}&to=${to}&monitorId=${monitorId}&size=${size}` - ); + const apiResponse = await supertest.get(API_URLS.PINGS).query({ + from, + to, + monitorId, + size, + }); const { total, pings } = decodePingsResponseData(apiResponse.body); @@ -160,9 +170,13 @@ export default function ({ getService }: FtrProviderContext) { const size = 5; const sort = 'asc'; - const apiResponse = await supertest.get( - `/api/uptime/pings?from=${from}&to=${to}&monitorId=${monitorId}&size=${size}&sort=${sort}` - ); + const apiResponse = await supertest.get(API_URLS.PINGS).query({ + from, + to, + monitorId, + size, + sort, + }); const { total, pings } = decodePingsResponseData(apiResponse.body); diff --git a/x-pack/test/api_integration/apis/uptime/rest/snapshot.ts b/x-pack/test/api_integration/apis/uptime/rest/snapshot.ts index 59393f7a4acf1..e7f604116e305 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/snapshot.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/snapshot.ts @@ -8,6 +8,7 @@ import { expectFixtureEql } from './helper/expect_fixture_eql'; import { FtrProviderContext } from '../../../ftr_provider_context'; import { makeChecksWithStatus, getChecksDateRange } from './helper/make_checks'; +import { API_URLS } from '../../../../../plugins/uptime/common/constants'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); @@ -18,9 +19,10 @@ export default function ({ getService }: FtrProviderContext) { describe('when no data is present', async () => { it('returns a null snapshot', async () => { - const apiResponse = await supertest.get( - `/api/uptime/snapshot/count?dateRangeStart=${dateRangeStart}&dateRangeEnd=${dateRangeEnd}` - ); + const apiResponse = await supertest.get(API_URLS.SNAPSHOT_COUNT).query({ + dateRangeStart, + dateRangeEnd, + }); expectFixtureEql(apiResponse.body, 'snapshot_empty'); }); @@ -75,9 +77,10 @@ export default function ({ getService }: FtrProviderContext) { }); it('will count all statuses correctly', async () => { - const apiResponse = await supertest.get( - `/api/uptime/snapshot/count?dateRangeStart=${dateRange.start}&dateRangeEnd=${dateRange.end}` - ); + const apiResponse = await supertest.get(API_URLS.SNAPSHOT_COUNT).query({ + dateRangeStart: dateRange.start, + dateRangeEnd: dateRange.end, + }); expectFixtureEql(apiResponse.body, 'snapshot'); }); diff --git a/x-pack/test/apm_api_integration/tests/csm/csm_services.spec.ts b/x-pack/test/apm_api_integration/tests/csm/csm_services.spec.ts index 2d5f0ddf1cd4c..657e2485e1c21 100644 --- a/x-pack/test/apm_api_integration/tests/csm/csm_services.spec.ts +++ b/x-pack/test/apm_api_integration/tests/csm/csm_services.spec.ts @@ -14,9 +14,11 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext) registry.when('CSM Services without data', { config: 'trial', archives: [] }, () => { it('returns empty list', async () => { - const response = await supertest.get( - '/api/apm/rum-client/services?start=2020-06-28T10%3A24%3A46.055Z&end=2020-07-29T10%3A24%3A46.055Z&uiFilters=%7B%22agentName%22%3A%5B%22js-base%22%2C%22rum-js%22%5D%7D' - ); + const response = await supertest.get('/internal/apm/ux/services').query({ + start: '2020-06-28T10:24:46.055Z', + end: '2020-07-29T10:24:46.055Z', + uiFilters: '{"agentName":["js-base","rum-js"]}', + }); expect(response.status).to.be(200); expect(response.body.rumServices).to.eql([]); @@ -28,9 +30,11 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext) { config: 'trial', archives: ['8.0.0', 'rum_8.0.0'] }, () => { it('returns rum services list', async () => { - const response = await supertest.get( - '/api/apm/rum-client/services?start=2020-06-28T10%3A24%3A46.055Z&end=2020-07-29T10%3A24%3A46.055Z&uiFilters=%7B%22agentName%22%3A%5B%22js-base%22%2C%22rum-js%22%5D%7D' - ); + const response = await supertest.get('/internal/apm/ux/services').query({ + start: '2020-06-28T10:24:46.055Z', + end: '2020-07-29T10:24:46.055Z', + uiFilters: '{"agentName":["js-base","rum-js"]}', + }); expect(response.status).to.be(200); diff --git a/x-pack/test/apm_api_integration/tests/csm/js_errors.spec.ts b/x-pack/test/apm_api_integration/tests/csm/js_errors.spec.ts index 5e4f306552273..b23f365348328 100644 --- a/x-pack/test/apm_api_integration/tests/csm/js_errors.spec.ts +++ b/x-pack/test/apm_api_integration/tests/csm/js_errors.spec.ts @@ -14,9 +14,13 @@ export default function rumJsErrorsApiTests({ getService }: FtrProviderContext) registry.when('CSM JS errors with data', { config: 'trial', archives: [] }, () => { it('returns no js errors', async () => { - const response = await supertest.get( - '/api/apm/rum-client/js-errors?pageSize=5&pageIndex=0&start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-14T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22elastic-co-rum-test%22%5D%7D' - ); + const response = await supertest.get('/internal/apm/ux/js-errors').query({ + pageSize: 5, + pageIndex: 0, + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-14T20:35:54.654Z', + uiFilters: '{"serviceName":["elastic-co-rum-test"]}', + }); expect(response.status).to.be(200); expectSnapshot(response.body).toMatchInline(` @@ -34,9 +38,13 @@ export default function rumJsErrorsApiTests({ getService }: FtrProviderContext) { config: 'trial', archives: ['8.0.0', 'rum_test_data'] }, () => { it('returns js errors', async () => { - const response = await supertest.get( - '/api/apm/rum-client/js-errors?start=2021-01-18T12%3A20%3A17.202Z&end=2021-01-18T12%3A25%3A17.203Z&uiFilters=%7B%22environment%22%3A%22ENVIRONMENT_ALL%22%2C%22serviceName%22%3A%5B%22elastic-co-frontend%22%5D%7D&pageSize=5&pageIndex=0' - ); + const response = await supertest.get('/internal/apm/ux/js-errors').query({ + start: '2021-01-18T12:20:17.202Z', + end: '2021-01-18T12:25:17.203Z', + uiFilters: '{"environment":"ENVIRONMENT_ALL","serviceName":["elastic-co-frontend"]}', + pageSize: 5, + pageIndex: 0, + }); expect(response.status).to.be(200); diff --git a/x-pack/test/apm_api_integration/tests/csm/long_task_metrics.spec.ts b/x-pack/test/apm_api_integration/tests/csm/long_task_metrics.spec.ts index ef1e537585b79..756d10bc4558d 100644 --- a/x-pack/test/apm_api_integration/tests/csm/long_task_metrics.spec.ts +++ b/x-pack/test/apm_api_integration/tests/csm/long_task_metrics.spec.ts @@ -14,9 +14,11 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext) registry.when('CSM long task metrics without data', { config: 'trial', archives: [] }, () => { it('returns empty list', async () => { - const response = await supertest.get( - '/api/apm/rum-client/long-task-metrics?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-14T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22elastic-co-rum-test%22%5D%7D' - ); + const response = await supertest.get('/internal/apm/ux/long-task-metrics').query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-14T20:35:54.654Z', + uiFilters: '{"serviceName":["elastic-co-rum-test"]}', + }); expect(response.status).to.be(200); expect(response.body).to.eql({ @@ -32,9 +34,11 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext) { config: 'trial', archives: ['8.0.0', 'rum_8.0.0'] }, () => { it('returns web core vitals values', async () => { - const response = await supertest.get( - '/api/apm/rum-client/long-task-metrics?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-16T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22kibana-frontend-8_0_0%22%5D%7D' - ); + const response = await supertest.get('/internal/apm/ux/long-task-metrics').query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-16T20:35:54.654Z', + uiFilters: '{"serviceName":["kibana-frontend-8_0_0"]}', + }); expect(response.status).to.be(200); diff --git a/x-pack/test/apm_api_integration/tests/csm/page_load_dist.spec.ts b/x-pack/test/apm_api_integration/tests/csm/page_load_dist.spec.ts index 1177b331c4c35..fd75a5cef33a2 100644 --- a/x-pack/test/apm_api_integration/tests/csm/page_load_dist.spec.ts +++ b/x-pack/test/apm_api_integration/tests/csm/page_load_dist.spec.ts @@ -14,18 +14,25 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext) registry.when('UX page load dist without data', { config: 'trial', archives: [] }, () => { it('returns empty list', async () => { - const response = await supertest.get( - '/api/apm/rum-client/page-load-distribution?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-14T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22elastic-co-rum-test%22%5D%7D' - ); + const response = await supertest.get('/internal/apm/ux/page-load-distribution').query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-14T20:35:54.654Z', + uiFilters: '{"serviceName":["elastic-co-rum-test"]}', + }); expect(response.status).to.be(200); expectSnapshot(response.body).toMatch(); }); it('returns empty list with breakdowns', async () => { - const response = await supertest.get( - '/api/apm/rum-client/page-load-distribution/breakdown?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-14T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22elastic-co-rum-test%22%5D%7D&breakdown=Browser' - ); + const response = await supertest + .get('/internal/apm/ux/page-load-distribution/breakdown') + .query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-14T20:35:54.654Z', + uiFilters: '{"serviceName":["elastic-co-rum-test"]}', + breakdown: 'Browser', + }); expect(response.status).to.be(200); expectSnapshot(response.body).toMatch(); @@ -37,18 +44,25 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext) { config: 'trial', archives: ['8.0.0', 'rum_8.0.0'] }, () => { it('returns page load distribution', async () => { - const response = await supertest.get( - '/api/apm/rum-client/page-load-distribution?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-16T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22kibana-frontend-8_0_0%22%5D%7D' - ); + const response = await supertest.get('/internal/apm/ux/page-load-distribution').query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-16T20:35:54.654Z', + uiFilters: '{"serviceName":["kibana-frontend-8_0_0"]}', + }); expect(response.status).to.be(200); expectSnapshot(response.body).toMatch(); }); it('returns page load distribution with breakdown', async () => { - const response = await supertest.get( - '/api/apm/rum-client/page-load-distribution/breakdown?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-16T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22kibana-frontend-8_0_0%22%5D%7D&breakdown=Browser' - ); + const response = await supertest + .get('/internal/apm/ux/page-load-distribution/breakdown') + .query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-16T20:35:54.654Z', + uiFilters: '{"serviceName":["kibana-frontend-8_0_0"]}', + breakdown: 'Browser', + }); expect(response.status).to.be(200); diff --git a/x-pack/test/apm_api_integration/tests/csm/page_views.spec.ts b/x-pack/test/apm_api_integration/tests/csm/page_views.spec.ts index 40aa88aa5ad82..f699fc9f8a3b1 100644 --- a/x-pack/test/apm_api_integration/tests/csm/page_views.spec.ts +++ b/x-pack/test/apm_api_integration/tests/csm/page_views.spec.ts @@ -14,18 +14,23 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext) registry.when('CSM page views without data', { config: 'trial', archives: [] }, () => { it('returns empty list', async () => { - const response = await supertest.get( - '/api/apm/rum-client/page-view-trends?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-14T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22elastic-co-rum-test%22%5D%7D' - ); + const response = await supertest.get('/internal/apm/ux/page-view-trends').query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-14T20:35:54.654Z', + uiFilters: '{"serviceName":["elastic-co-rum-test"]}', + }); expect(response.status).to.be(200); expectSnapshot(response.body).toMatch(); }); it('returns empty list with breakdowns', async () => { - const response = await supertest.get( - '/api/apm/rum-client/page-view-trends?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-14T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22elastic-co-rum-test%22%5D%7D&breakdowns=%7B%22name%22%3A%22Browser%22%2C%22fieldName%22%3A%22user_agent.name%22%2C%22type%22%3A%22category%22%7D' - ); + const response = await supertest.get('/internal/apm/ux/page-view-trends').query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-14T20:35:54.654Z', + uiFilters: '{"serviceName":["elastic-co-rum-test"]}', + breakdowns: '{"name":"Browser","fieldName":"user_agent.name","type":"category"}', + }); expect(response.status).to.be(200); expectSnapshot(response.body).toMatch(); @@ -37,18 +42,23 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext) { config: 'trial', archives: ['8.0.0', 'rum_8.0.0'] }, () => { it('returns page views', async () => { - const response = await supertest.get( - '/api/apm/rum-client/page-view-trends?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-16T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22kibana-frontend-8_0_0%22%5D%7D' - ); + const response = await supertest.get('/internal/apm/ux/page-view-trends').query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-16T20:35:54.654Z', + uiFilters: '{"serviceName":["kibana-frontend-8_0_0"]}', + }); expect(response.status).to.be(200); expectSnapshot(response.body).toMatch(); }); it('returns page views with breakdown', async () => { - const response = await supertest.get( - '/api/apm/rum-client/page-view-trends?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-16T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22kibana-frontend-8_0_0%22%5D%7D&breakdowns=%7B%22name%22%3A%22Browser%22%2C%22fieldName%22%3A%22user_agent.name%22%2C%22type%22%3A%22category%22%7D' - ); + const response = await supertest.get('/internal/apm/ux/page-view-trends').query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-16T20:35:54.654Z', + uiFilters: '{"serviceName":["kibana-frontend-8_0_0"]}', + breakdowns: '{"name":"Browser","fieldName":"user_agent.name","type":"category"}', + }); expect(response.status).to.be(200); diff --git a/x-pack/test/apm_api_integration/tests/csm/url_search.spec.ts b/x-pack/test/apm_api_integration/tests/csm/url_search.spec.ts index f45e82865983e..89e56face9343 100644 --- a/x-pack/test/apm_api_integration/tests/csm/url_search.spec.ts +++ b/x-pack/test/apm_api_integration/tests/csm/url_search.spec.ts @@ -14,9 +14,12 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext) registry.when('CSM url search api without data', { config: 'trial', archives: [] }, () => { it('returns empty list', async () => { - const response = await supertest.get( - '/api/apm/rum-client/url-search?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-14T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22elastic-co-rum-test%22%5D%7D&percentile=50' - ); + const response = await supertest.get('/internal/apm/ux/url-search').query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-14T20:35:54.654Z', + uiFilters: '{"serviceName":["elastic-co-rum-test"]}', + percentile: 50, + }); expect(response.status).to.be(200); expectSnapshot(response.body).toMatchInline(` @@ -33,9 +36,12 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext) { config: 'trial', archives: ['8.0.0', 'rum_8.0.0'] }, () => { it('returns top urls when no query', async () => { - const response = await supertest.get( - '/api/apm/rum-client/url-search?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-16T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22kibana-frontend-8_0_0%22%5D%7D&percentile=50' - ); + const response = await supertest.get('/internal/apm/ux/url-search').query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-16T20:35:54.654Z', + uiFilters: '{"serviceName":["kibana-frontend-8_0_0"]}', + percentile: 50, + }); expect(response.status).to.be(200); @@ -59,9 +65,13 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext) }); it('returns specific results against query', async () => { - const response = await supertest.get( - '/api/apm/rum-client/url-search?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-16T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22kibana-frontend-8_0_0%22%5D%7D&urlQuery=csm&percentile=50' - ); + const response = await supertest.get('/internal/apm/ux/url-search').query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-16T20:35:54.654Z', + uiFilters: '{"serviceName":["kibana-frontend-8_0_0"]}', + urlQuery: 'csm', + percentile: 50, + }); expect(response.status).to.be(200); diff --git a/x-pack/test/apm_api_integration/tests/csm/web_core_vitals.spec.ts b/x-pack/test/apm_api_integration/tests/csm/web_core_vitals.spec.ts index 421bafcb4064f..882e9e23a4314 100644 --- a/x-pack/test/apm_api_integration/tests/csm/web_core_vitals.spec.ts +++ b/x-pack/test/apm_api_integration/tests/csm/web_core_vitals.spec.ts @@ -14,9 +14,12 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext) registry.when('CSM web core vitals without data', { config: 'trial', archives: [] }, () => { it('returns empty list', async () => { - const response = await supertest.get( - '/api/apm/rum-client/web-core-vitals?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-14T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22elastic-co-rum-test%22%5D%7D&percentile=50' - ); + const response = await supertest.get('/internal/apm/ux/web-core-vitals').query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-14T20:35:54.654Z', + uiFilters: '{"serviceName":["elastic-co-rum-test"]}', + percentile: 50, + }); expect(response.status).to.be(200); expect(response.body).to.eql({ @@ -35,9 +38,12 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext) { config: 'trial', archives: ['8.0.0', 'rum_8.0.0'] }, () => { it('returns web core vitals values', async () => { - const response = await supertest.get( - '/api/apm/rum-client/web-core-vitals?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-16T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22kibana-frontend-8_0_0%22%5D%7D&percentile=50' - ); + const response = await supertest.get('/internal/apm/ux/web-core-vitals').query({ + start: '2020-09-07T20:35:54.654Z', + end: '2020-09-16T20:35:54.654Z', + uiFilters: '{"serviceName":["kibana-frontend-8_0_0"]}', + percentile: 50, + }); expect(response.status).to.be(200); From 77a620c07076ed9e5059c6cb7485bfe090e26ff1 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Thu, 11 Nov 2021 14:14:05 +0100 Subject: [PATCH 47/51] [APM] Reinstate ML multi-metric job (#117836) Closes #101734. This reverts commit 008421f. Additionally, incorporate suggested changes from #101734 (comment). --- .../anomaly_detection/apm_ml_anomaly_query.ts | 27 +++++ .../anomaly_detection/apm_ml_detectors.ts | 12 +++ .../index.ts} | 6 +- .../create_anomaly_detection_jobs.ts | 20 ++-- .../lib/service_map/get_service_anomalies.ts | 4 +- .../transactions/get_anomaly_data/fetcher.ts | 4 +- .../modules/apm_transaction/manifest.json | 18 ++-- .../apm_transaction/ml/apm_tx_metrics.json | 53 ++++++++++ .../ml/datafeed_apm_tx_metrics.json | 98 +++++++++++++++++++ ...tafeed_high_mean_transaction_duration.json | 17 ---- .../ml/high_mean_transaction_duration.json | 35 ------- .../apis/ml/modules/recognize_module.ts | 2 +- .../apis/ml/modules/setup_module.ts | 10 +- 13 files changed, 225 insertions(+), 81 deletions(-) create mode 100644 x-pack/plugins/apm/common/anomaly_detection/apm_ml_anomaly_query.ts create mode 100644 x-pack/plugins/apm/common/anomaly_detection/apm_ml_detectors.ts rename x-pack/plugins/apm/common/{anomaly_detection.ts => anomaly_detection/index.ts} (93%) create mode 100644 x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/apm_tx_metrics.json create mode 100644 x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/datafeed_apm_tx_metrics.json delete mode 100644 x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/datafeed_high_mean_transaction_duration.json delete mode 100644 x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/high_mean_transaction_duration.json diff --git a/x-pack/plugins/apm/common/anomaly_detection/apm_ml_anomaly_query.ts b/x-pack/plugins/apm/common/anomaly_detection/apm_ml_anomaly_query.ts new file mode 100644 index 0000000000000..00fb4b5ee4a54 --- /dev/null +++ b/x-pack/plugins/apm/common/anomaly_detection/apm_ml_anomaly_query.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ApmMlDetectorIndex } from './apm_ml_detectors'; + +export function apmMlAnomalyQuery(detectorIndex: ApmMlDetectorIndex) { + return [ + { + bool: { + filter: [ + { + terms: { + result_type: ['model_plot', 'record'], + }, + }, + { + term: { detector_index: detectorIndex }, + }, + ], + }, + }, + ]; +} diff --git a/x-pack/plugins/apm/common/anomaly_detection/apm_ml_detectors.ts b/x-pack/plugins/apm/common/anomaly_detection/apm_ml_detectors.ts new file mode 100644 index 0000000000000..7c68232122408 --- /dev/null +++ b/x-pack/plugins/apm/common/anomaly_detection/apm_ml_detectors.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const enum ApmMlDetectorIndex { + txLatency = 0, + txThroughput = 1, + txFailureRate = 2, +} diff --git a/x-pack/plugins/apm/common/anomaly_detection.ts b/x-pack/plugins/apm/common/anomaly_detection/index.ts similarity index 93% rename from x-pack/plugins/apm/common/anomaly_detection.ts rename to x-pack/plugins/apm/common/anomaly_detection/index.ts index 43a779407d2a4..cdb1c62b9eed5 100644 --- a/x-pack/plugins/apm/common/anomaly_detection.ts +++ b/x-pack/plugins/apm/common/anomaly_detection/index.ts @@ -6,12 +6,12 @@ */ import { i18n } from '@kbn/i18n'; -import { ANOMALY_SEVERITY } from './ml_constants'; +import { ANOMALY_SEVERITY } from '../ml_constants'; import { getSeverityType, getSeverityColor as mlGetSeverityColor, -} from '../../ml/common'; -import { ServiceHealthStatus } from './service_health_status'; +} from '../../../ml/common'; +import { ServiceHealthStatus } from '../service_health_status'; export interface ServiceAnomalyStats { transactionType?: string; diff --git a/x-pack/plugins/apm/server/lib/anomaly_detection/create_anomaly_detection_jobs.ts b/x-pack/plugins/apm/server/lib/anomaly_detection/create_anomaly_detection_jobs.ts index 9d6abad0ff6a6..7277a12c2bf14 100644 --- a/x-pack/plugins/apm/server/lib/anomaly_detection/create_anomaly_detection_jobs.ts +++ b/x-pack/plugins/apm/server/lib/anomaly_detection/create_anomaly_detection_jobs.ts @@ -5,21 +5,21 @@ * 2.0. */ +import Boom from '@hapi/boom'; import { Logger } from 'kibana/server'; -import uuid from 'uuid/v4'; import { snakeCase } from 'lodash'; -import Boom from '@hapi/boom'; import moment from 'moment'; +import uuid from 'uuid/v4'; import { ML_ERRORS } from '../../../common/anomaly_detection'; -import { ProcessorEvent } from '../../../common/processor_event'; -import { environmentQuery } from '../../../common/utils/environment_query'; -import { Setup } from '../helpers/setup_request'; import { - TRANSACTION_DURATION, + METRICSET_NAME, PROCESSOR_EVENT, } from '../../../common/elasticsearch_fieldnames'; -import { APM_ML_JOB_GROUP, ML_MODULE_ID_APM_TRANSACTION } from './constants'; +import { ProcessorEvent } from '../../../common/processor_event'; +import { environmentQuery } from '../../../common/utils/environment_query'; import { withApmSpan } from '../../utils/with_apm_span'; +import { Setup } from '../helpers/setup_request'; +import { APM_ML_JOB_GROUP, ML_MODULE_ID_APM_TRANSACTION } from './constants'; import { getAnomalyDetectionJobs } from './get_anomaly_detection_jobs'; export async function createAnomalyDetectionJobs( @@ -92,8 +92,8 @@ async function createAnomalyDetectionJob({ query: { bool: { filter: [ - { term: { [PROCESSOR_EVENT]: ProcessorEvent.transaction } }, - { exists: { field: TRANSACTION_DURATION } }, + { term: { [PROCESSOR_EVENT]: ProcessorEvent.metric } }, + { term: { [METRICSET_NAME]: 'transaction' } }, ...environmentQuery(environment), ], }, @@ -105,7 +105,7 @@ async function createAnomalyDetectionJob({ job_tags: { environment, // identifies this as an APM ML job & facilitates future migrations - apm_ml_version: 2, + apm_ml_version: 3, }, }, }, diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts index 2ed1966dcacbd..2aa2f5c6eead5 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts @@ -22,6 +22,8 @@ import { rangeQuery } from '../../../../observability/server'; import { withApmSpan } from '../../utils/with_apm_span'; import { getMlJobsWithAPMGroup } from '../anomaly_detection/get_ml_jobs_with_apm_group'; import { Setup } from '../helpers/setup_request'; +import { apmMlAnomalyQuery } from '../../../common/anomaly_detection/apm_ml_anomaly_query'; +import { ApmMlDetectorIndex } from '../../../common/anomaly_detection/apm_ml_detectors'; export const DEFAULT_ANOMALIES: ServiceAnomaliesResponse = { mlJobIds: [], @@ -56,7 +58,7 @@ export async function getServiceAnomalies({ query: { bool: { filter: [ - { terms: { result_type: ['model_plot', 'record'] } }, + ...apmMlAnomalyQuery(ApmMlDetectorIndex.txLatency), ...rangeQuery( Math.min(end - 30 * 60 * 1000, start), end, diff --git a/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/fetcher.ts b/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/fetcher.ts index 2fcbf5842d746..dd723f24abe1b 100644 --- a/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/fetcher.ts @@ -12,6 +12,8 @@ import { rangeQuery } from '../../../../../observability/server'; import { asMutableArray } from '../../../../common/utils/as_mutable_array'; import { withApmSpan } from '../../../utils/with_apm_span'; import { Setup } from '../../helpers/setup_request'; +import { apmMlAnomalyQuery } from '../../../../common/anomaly_detection/apm_ml_anomaly_query'; +import { ApmMlDetectorIndex } from '../../../../common/anomaly_detection/apm_ml_detectors'; export type ESResponse = Exclude< PromiseReturnType, @@ -40,7 +42,7 @@ export function anomalySeriesFetcher({ query: { bool: { filter: [ - { terms: { result_type: ['model_plot', 'record'] } }, + ...apmMlAnomalyQuery(ApmMlDetectorIndex.txLatency), { term: { partition_field_value: serviceName } }, { term: { by_field_value: transactionType } }, ...rangeQuery(start, end, 'timestamp'), diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/manifest.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/manifest.json index f8feaef3be5f8..3332fad66b3e2 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/manifest.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/manifest.json @@ -1,29 +1,29 @@ { "id": "apm_transaction", "title": "APM", - "description": "Detect anomalies in transactions from your APM services.", + "description": "Detect anomalies in transaction latency, throughput and failure rate from your APM services for metric data.", "type": "Transaction data", "logoFile": "logo.json", - "defaultIndexPattern": "apm-*-transaction", + "defaultIndexPattern": "apm-*-metric,metrics-apm*", "query": { "bool": { "filter": [ - { "term": { "processor.event": "transaction" } }, - { "exists": { "field": "transaction.duration" } } + { "term": { "processor.event": "metric" } }, + { "term": { "metricset.name": "transaction" } } ] } }, "jobs": [ { - "id": "high_mean_transaction_duration", - "file": "high_mean_transaction_duration.json" + "id": "apm_tx_metrics", + "file": "apm_tx_metrics.json" } ], "datafeeds": [ { - "id": "datafeed-high_mean_transaction_duration", - "file": "datafeed_high_mean_transaction_duration.json", - "job_id": "high_mean_transaction_duration" + "id": "datafeed-apm_tx_metrics", + "file": "datafeed_apm_tx_metrics.json", + "job_id": "apm_tx_metrics" } ] } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/apm_tx_metrics.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/apm_tx_metrics.json new file mode 100644 index 0000000000000..f93b4fb009a14 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/apm_tx_metrics.json @@ -0,0 +1,53 @@ +{ + "job_type": "anomaly_detector", + "groups": [ + "apm" + ], + "description": "Detects anomalies in transaction latency, throughput and error percentage for metric data.", + "analysis_config": { + "bucket_span": "15m", + "summary_count_field_name" : "doc_count", + "detectors" : [ + { + "detector_description" : "high latency by transaction type for an APM service", + "function" : "high_mean", + "field_name" : "transaction_latency", + "by_field_name" : "transaction.type", + "partition_field_name" : "service.name" + }, + { + "detector_description" : "transaction throughput for an APM service", + "function" : "mean", + "field_name" : "transaction_throughput", + "by_field_name" : "transaction.type", + "partition_field_name" : "service.name" + }, + { + "detector_description" : "failed transaction rate for an APM service", + "function" : "high_mean", + "field_name" : "failed_transaction_rate", + "by_field_name" : "transaction.type", + "partition_field_name" : "service.name" + } + ], + "influencers" : [ + "transaction.type", + "service.name" + ] + }, + "analysis_limits": { + "model_memory_limit": "32mb" + }, + "data_description": { + "time_field" : "@timestamp", + "time_format" : "epoch_ms" + }, + "model_plot_config": { + "enabled" : true, + "annotations_enabled" : true + }, + "results_index_name" : "custom-apm", + "custom_settings": { + "created_by": "ml-module-apm-transaction" + } +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/datafeed_apm_tx_metrics.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/datafeed_apm_tx_metrics.json new file mode 100644 index 0000000000000..4d19cdc9f533d --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/datafeed_apm_tx_metrics.json @@ -0,0 +1,98 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "chunking_config" : { + "mode" : "off" + }, + "query": { + "bool": { + "filter": [ + { "term": { "processor.event": "metric" } }, + { "term": { "metricset.name": "transaction" } } + ] + } + }, + "aggregations" : { + "buckets" : { + "composite" : { + "size" : 5000, + "sources" : [ + { + "date" : { + "date_histogram" : { + "field" : "@timestamp", + "fixed_interval" : "90s" + } + } + }, + { + "transaction.type" : { + "terms" : { + "field" : "transaction.type" + } + } + }, + { + "service.name" : { + "terms" : { + "field" : "service.name" + } + } + } + ] + }, + "aggs" : { + "@timestamp" : { + "max" : { + "field" : "@timestamp" + } + }, + "transaction_throughput" : { + "rate" : { + "unit" : "minute" + } + }, + "transaction_latency" : { + "avg" : { + "field" : "transaction.duration.histogram" + } + }, + "error_count" : { + "filter" : { + "term" : { + "event.outcome" : "failure" + } + }, + "aggs" : { + "actual_error_count" : { + "value_count" : { + "field" : "event.outcome" + } + } + } + }, + "success_count" : { + "filter" : { + "term" : { + "event.outcome" : "success" + } + } + }, + "failed_transaction_rate" : { + "bucket_script" : { + "buckets_path" : { + "failure_count" : "error_count>_count", + "success_count" : "success_count>_count" + }, + "script" : "if ((params.failure_count + params.success_count)==0){return 0;}else{return 100 * (params.failure_count/(params.failure_count + params.success_count));}" + } + } + } + } + }, + "indices_options": { + "ignore_unavailable": true + } +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/datafeed_high_mean_transaction_duration.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/datafeed_high_mean_transaction_duration.json deleted file mode 100644 index 882bd93fd937d..0000000000000 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/datafeed_high_mean_transaction_duration.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "job_id": "JOB_ID", - "indices": [ - "INDEX_PATTERN_NAME" - ], - "query": { - "bool": { - "filter": [ - { "term": { "processor.event": "transaction" } }, - { "exists": { "field": "transaction.duration.us" } } - ] - } - }, - "indices_options": { - "ignore_unavailable": true - } -} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/high_mean_transaction_duration.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/high_mean_transaction_duration.json deleted file mode 100644 index 77284cb275cd8..0000000000000 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/high_mean_transaction_duration.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "job_type": "anomaly_detector", - "groups": [ - "apm" - ], - "description": "Detect transaction duration anomalies across transaction types for your APM services.", - "analysis_config": { - "bucket_span": "15m", - "detectors": [ - { - "detector_description": "high duration by transaction type for an APM service", - "function": "high_mean", - "field_name": "transaction.duration.us", - "by_field_name": "transaction.type", - "partition_field_name": "service.name" - } - ], - "influencers": [ - "transaction.type", - "service.name" - ] - }, - "analysis_limits": { - "model_memory_limit": "32mb" - }, - "data_description": { - "time_field": "@timestamp" - }, - "model_plot_config": { - "enabled": true - }, - "custom_settings": { - "created_by": "ml-module-apm-transaction" - } -} diff --git a/x-pack/test/api_integration/apis/ml/modules/recognize_module.ts b/x-pack/test/api_integration/apis/ml/modules/recognize_module.ts index 2742fbff294c0..00b820a025c8b 100644 --- a/x-pack/test/api_integration/apis/ml/modules/recognize_module.ts +++ b/x-pack/test/api_integration/apis/ml/modules/recognize_module.ts @@ -44,7 +44,7 @@ export default ({ getService }: FtrProviderContext) => { user: USER.ML_POWERUSER, expected: { responseCode: 200, - moduleIds: ['apm_jsbase', 'apm_transaction', 'apm_nodejs'], + moduleIds: ['apm_jsbase', 'apm_nodejs'], }, }, { diff --git a/x-pack/test/api_integration/apis/ml/modules/setup_module.ts b/x-pack/test/api_integration/apis/ml/modules/setup_module.ts index c538fc0d9cb55..07a02911c6778 100644 --- a/x-pack/test/api_integration/apis/ml/modules/setup_module.ts +++ b/x-pack/test/api_integration/apis/ml/modules/setup_module.ts @@ -187,9 +187,11 @@ export default ({ getService }: FtrProviderContext) => { dashboards: [] as string[], }, }, + // Set startDatafeed and estimateModelMemory to false for the APM transaction test + // until there is a new data set available with metric data. { testTitleSuffix: - 'for apm_transaction with prefix, startDatafeed true and estimateModelMemory true', + 'for apm_transaction with prefix, startDatafeed false and estimateModelMemory false', sourceDataArchive: 'x-pack/test/functional/es_archives/ml/module_apm', indexPattern: { name: 'ft_module_apm', timeField: '@timestamp' }, module: 'apm_transaction', @@ -197,14 +199,14 @@ export default ({ getService }: FtrProviderContext) => { requestBody: { prefix: 'pf5_', indexPatternName: 'ft_module_apm', - startDatafeed: true, - end: Date.now(), + startDatafeed: false, + estimateModelMemory: false, }, expected: { responseCode: 200, jobs: [ { - jobId: 'pf5_high_mean_transaction_duration', + jobId: 'pf5_apm_tx_metrics', jobState: JOB_STATE.CLOSED, datafeedState: DATAFEED_STATE.STOPPED, }, From 589cf5bcb88ac10a1620fd93e170947a823cc9c7 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Thu, 11 Nov 2021 13:19:38 +0000 Subject: [PATCH 48/51] skip flaky suites (#100570) --- x-pack/test/functional/apps/spaces/enter_space.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/spaces/enter_space.ts b/x-pack/test/functional/apps/spaces/enter_space.ts index d58a5c0f19f39..7a3ffc50a4821 100644 --- a/x-pack/test/functional/apps/spaces/enter_space.ts +++ b/x-pack/test/functional/apps/spaces/enter_space.ts @@ -14,7 +14,8 @@ export default function enterSpaceFunctonalTests({ const esArchiver = getService('esArchiver'); const PageObjects = getPageObjects(['security', 'spaceSelector']); - describe('Enter Space', function () { + // FLAKY: https://github.com/elastic/kibana/issues/100570 + describe.skip('Enter Space', function () { this.tags('includeFirefox'); before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/spaces/enter_space'); From 744530ecdb72aa1c8627f2f1e9d61becb94977be Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau Date: Thu, 11 Nov 2021 08:44:47 -0500 Subject: [PATCH 49/51] [SECURITY] Don't use link for the last breadcrumb in the navigation bar for Security/Spaces management apps (#118117) * fix last breadcrumb item to only be text * commit using @elastic.co * cleaner * tests are coming ;) * used my brain to simplify it * fix types * fix/add jest test * fix lint + jest tests for spaces * fix accessibality --- .../public/components/breadcrumb.test.tsx | 75 +++++++++++++ .../security/public/components/breadcrumb.tsx | 10 +- .../api_keys/api_keys_management_app.test.tsx | 2 +- .../role_mappings_management_app.test.tsx | 40 ++++--- .../role_mappings_management_app.tsx | 87 +++++++-------- .../roles/roles_management_app.test.tsx | 43 ++++---- .../management/roles/roles_management_app.tsx | 102 +++++++++--------- .../users/users_management_app.test.tsx | 19 ++-- .../management/users/users_management_app.tsx | 1 - .../management/spaces_management_app.test.tsx | 6 +- .../management/spaces_management_app.tsx | 18 ++-- x-pack/test/accessibility/apps/users.ts | 3 + 12 files changed, 245 insertions(+), 161 deletions(-) create mode 100644 x-pack/plugins/security/public/components/breadcrumb.test.tsx diff --git a/x-pack/plugins/security/public/components/breadcrumb.test.tsx b/x-pack/plugins/security/public/components/breadcrumb.test.tsx new file mode 100644 index 0000000000000..00cd4be90a780 --- /dev/null +++ b/x-pack/plugins/security/public/components/breadcrumb.test.tsx @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { render } from '@testing-library/react'; +import React from 'react'; + +import { coreMock } from 'src/core/public/mocks'; + +import { Breadcrumb, BreadcrumbsProvider, createBreadcrumbsChangeHandler } from './breadcrumb'; + +describe('security breadcrumbs', () => { + const setBreadcrumbs = jest.fn(); + const { chrome } = coreMock.createStart(); + + beforeEach(() => { + setBreadcrumbs.mockReset(); + chrome.docTitle.reset.mockReset(); + chrome.docTitle.change.mockReset(); + }); + + it('rendering one breadcrumb and it should NOT have an href attributes', async () => { + render( + + +

    {'Find'}
    + + + ); + + expect(setBreadcrumbs).toHaveBeenCalledTimes(1); + expect(setBreadcrumbs).toHaveBeenCalledWith([{ text: 'Find' }]); + }); + + it('rendering two breadcrumb and our last breadcrumb should NOT have an href attributes', async () => { + render( + + +
    {'Find'}
    + +
    {'Sandy is a sweet dog'}
    +
    +
    +
    + ); + + expect(setBreadcrumbs).toHaveBeenCalledTimes(1); + expect(setBreadcrumbs).toHaveBeenCalledWith([{ href: '/', text: 'Find' }, { text: 'Sandy' }]); + }); + + it('rendering three breadcrumb and our last breadcrumb should NOT have an href attributes', async () => { + render( + + +
    {'Find'}
    + +
    {'Sandy is a sweet dog'}
    + +
    {'Sandy is a mutts'}
    +
    +
    +
    +
    + ); + + expect(setBreadcrumbs).toHaveBeenCalledTimes(1); + expect(setBreadcrumbs).toHaveBeenCalledWith([ + { href: '/', text: 'Find' }, + { href: '/sandy', text: 'Sandy' }, + { text: 'Breed' }, + ]); + }); +}); diff --git a/x-pack/plugins/security/public/components/breadcrumb.tsx b/x-pack/plugins/security/public/components/breadcrumb.tsx index 353f738501cbe..4706f60712ad5 100644 --- a/x-pack/plugins/security/public/components/breadcrumb.tsx +++ b/x-pack/plugins/security/public/components/breadcrumb.tsx @@ -80,11 +80,17 @@ export const BreadcrumbsProvider: FunctionComponent = const breadcrumbsRef = useRef([]); const handleChange = (breadcrumbs: BreadcrumbProps[]) => { + const newBreadcrumbs = breadcrumbs.map((item, index) => { + if (index === breadcrumbs.length - 1) { + return { ...item, href: undefined }; + } + return item; + }); if (onChange) { - onChange(breadcrumbs); + onChange(newBreadcrumbs); } else if (services.chrome) { const setBreadcrumbs = createBreadcrumbsChangeHandler(services.chrome); - setBreadcrumbs(breadcrumbs); + setBreadcrumbs(newBreadcrumbs); } }; diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx index d2611864e77a2..922fd59c56d1b 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx @@ -56,7 +56,7 @@ describe('apiKeysManagementApp', () => { }); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); - expect(setBreadcrumbs).toHaveBeenCalledWith([{ href: '/', text: 'API keys' }]); + expect(setBreadcrumbs).toHaveBeenCalledWith([{ text: 'API keys' }]); expect(docTitle.change).toHaveBeenCalledWith(['API keys']); expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(` diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx index e73abc3b1eeaf..f6d17327b7118 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx @@ -5,6 +5,14 @@ * 2.0. */ +import { act } from '@testing-library/react'; +import { noop } from 'lodash'; + +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; +import type { Unmount } from 'src/plugins/management/public/types'; + +import { roleMappingsManagementApp } from './role_mappings_management_app'; + jest.mock('./role_mappings_grid', () => ({ RoleMappingsGridPage: (props: any) => // `docLinks` object is too big to include into test snapshot, so we just check its existence. @@ -23,24 +31,23 @@ jest.mock('./edit_role_mapping', () => ({ })}`, })); -import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; - -import { roleMappingsManagementApp } from './role_mappings_management_app'; - async function mountApp(basePath: string, pathname: string) { const container = document.createElement('div'); const setBreadcrumbs = jest.fn(); const startServices = await coreMock.createSetup().getStartServices(); - const unmount = await roleMappingsManagementApp - .create({ getStartServices: () => Promise.resolve(startServices) as any }) - .mount({ - basePath, - element: container, - setBreadcrumbs, - history: scopedHistoryMock.create({ pathname }), - }); + let unmount: Unmount = noop; + await act(async () => { + unmount = await roleMappingsManagementApp + .create({ getStartServices: () => Promise.resolve(startServices) as any }) + .mount({ + basePath, + element: container, + setBreadcrumbs, + history: scopedHistoryMock.create({ pathname }), + }); + }); return { unmount, container, setBreadcrumbs, docTitle: startServices[0].chrome.docTitle }; } @@ -65,7 +72,7 @@ describe('roleMappingsManagementApp', () => { const { setBreadcrumbs, container, unmount, docTitle } = await mountApp('/', '/'); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); - expect(setBreadcrumbs).toHaveBeenCalledWith([{ href: `/`, text: 'Role Mappings' }]); + expect(setBreadcrumbs).toHaveBeenCalledWith([{ text: 'Role Mappings' }]); expect(docTitle.change).toHaveBeenCalledWith('Role Mappings'); expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(` @@ -114,8 +121,8 @@ describe('roleMappingsManagementApp', () => { expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([ - { href: `/`, text: 'Role Mappings' }, - { href: `/edit/${encodeURIComponent(roleMappingName)}`, text: roleMappingName }, + { href: '/', text: 'Role Mappings' }, + { text: roleMappingName }, ]); expect(docTitle.change).toHaveBeenCalledWith('Role Mappings'); expect(docTitle.reset).not.toHaveBeenCalled(); @@ -139,9 +146,8 @@ describe('roleMappingsManagementApp', () => { expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([ - { href: `/`, text: 'Role Mappings' }, + { href: '/', text: 'Role Mappings' }, { - href: '/edit/some%20%E5%AE%89%E5%85%A8%E6%80%A7%20role%20mapping', text: roleMappingName, }, ]); diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx index 4dfc9b43642bf..22d09e9e2a678 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx @@ -7,13 +7,18 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import { Route, Router, Switch, useParams } from 'react-router-dom'; +import { Route, Router, useParams } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; import type { StartServicesAccessor } from 'src/core/public'; import type { RegisterManagementAppArgs } from 'src/plugins/management/public'; import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; +import { + Breadcrumb, + BreadcrumbsProvider, + createBreadcrumbsChangeHandler, +} from '../../components/breadcrumb'; import type { PluginStartDependencies } from '../../plugin'; import { tryDecodeURIComponent } from '../url_utils'; @@ -27,21 +32,12 @@ export const roleMappingsManagementApp = Object.freeze({ const title = i18n.translate('xpack.security.management.roleMappingsTitle', { defaultMessage: 'Role Mappings', }); + return { id: this.id, order: 40, title, async mount({ element, setBreadcrumbs, history }) { - const [coreStart] = await getStartServices(); - const roleMappingsBreadcrumbs = [ - { - text: title, - href: `/`, - }, - ]; - - coreStart.chrome.docTitle.change(title); - const [ [core], { RoleMappingsGridPage }, @@ -56,20 +52,9 @@ export const roleMappingsManagementApp = Object.freeze({ import('../roles'), ]); + core.chrome.docTitle.change(title); + const roleMappingsAPIClient = new RoleMappingsAPIClient(core.http); - const RoleMappingsGridPageWithBreadcrumbs = () => { - setBreadcrumbs(roleMappingsBreadcrumbs); - return ( - - ); - }; const EditRoleMappingsPageWithBreadcrumbs = () => { const { name } = useParams<{ name?: string }>(); @@ -78,26 +63,26 @@ export const roleMappingsManagementApp = Object.freeze({ // See https://github.com/elastic/kibana/issues/82440 const decodedName = name ? tryDecodeURIComponent(name) : undefined; - setBreadcrumbs([ - ...roleMappingsBreadcrumbs, - name + const breadcrumbObj = + name && decodedName ? { text: decodedName, href: `/edit/${encodeURIComponent(name)}` } : { text: i18n.translate('xpack.security.roleMappings.createBreadcrumb', { defaultMessage: 'Create', }), - }, - ]); + }; return ( - + + + ); }; @@ -105,14 +90,25 @@ export const roleMappingsManagementApp = Object.freeze({ - - - - - - - - + + + + + + + + + + , @@ -120,7 +116,6 @@ export const roleMappingsManagementApp = Object.freeze({ ); return () => { - coreStart.chrome.docTitle.reset(); unmountComponentAtNode(element); }; }, diff --git a/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx b/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx index 4b10c2d5cf13b..faab47a858d67 100644 --- a/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx @@ -5,7 +5,11 @@ * 2.0. */ +import { act } from '@testing-library/react'; +import { noop } from 'lodash'; + import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; +import type { Unmount } from 'src/plugins/management/public/types'; import { featuresPluginMock } from '../../../../features/public/mocks'; import { licenseMock } from '../../../common/licensing/index.mock'; @@ -29,20 +33,23 @@ async function mountApp(basePath: string, pathname: string) { const featuresStart = featuresPluginMock.createStart(); const coreStart = coreMock.createStart(); - const unmount = await rolesManagementApp - .create({ - license: licenseMock.create(), - fatalErrors, - getStartServices: jest - .fn() - .mockResolvedValue([coreStart, { data: {}, features: featuresStart }]), - }) - .mount({ - basePath, - element: container, - setBreadcrumbs, - history: scopedHistoryMock.create({ pathname }), - }); + let unmount: Unmount = noop; + await act(async () => { + unmount = await rolesManagementApp + .create({ + license: licenseMock.create(), + fatalErrors, + getStartServices: jest + .fn() + .mockResolvedValue([coreStart, { data: {}, features: featuresStart }]), + }) + .mount({ + basePath, + element: container, + setBreadcrumbs, + history: scopedHistoryMock.create({ pathname }), + }); + }); return { unmount, container, setBreadcrumbs, docTitle: coreStart.chrome.docTitle }; } @@ -71,7 +78,7 @@ describe('rolesManagementApp', () => { const { setBreadcrumbs, container, unmount, docTitle } = await mountApp('/', '/'); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); - expect(setBreadcrumbs).toHaveBeenCalledWith([{ href: `/`, text: 'Roles' }]); + expect(setBreadcrumbs).toHaveBeenCalledWith([{ text: 'Roles' }]); expect(docTitle.change).toHaveBeenCalledWith('Roles'); expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(` @@ -116,10 +123,7 @@ describe('rolesManagementApp', () => { ); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); - expect(setBreadcrumbs).toHaveBeenCalledWith([ - { href: `/`, text: 'Roles' }, - { href: `/edit/${encodeURIComponent(roleName)}`, text: roleName }, - ]); + expect(setBreadcrumbs).toHaveBeenCalledWith([{ href: `/`, text: 'Roles' }, { text: roleName }]); expect(docTitle.change).toHaveBeenCalledWith('Roles'); expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(` @@ -169,7 +173,6 @@ describe('rolesManagementApp', () => { expect(setBreadcrumbs).toHaveBeenCalledWith([ { href: `/`, text: 'Roles' }, { - href: '/edit/some%20%E5%AE%89%E5%85%A8%E6%80%A7%20role', text: roleName, }, ]); diff --git a/x-pack/plugins/security/public/management/roles/roles_management_app.tsx b/x-pack/plugins/security/public/management/roles/roles_management_app.tsx index 8936f506066e0..fcd037a861ed0 100644 --- a/x-pack/plugins/security/public/management/roles/roles_management_app.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_management_app.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import { Route, Router, Switch, useParams } from 'react-router-dom'; +import { Route, Router, useParams } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; import type { FatalErrorsSetup, StartServicesAccessor } from 'src/core/public'; @@ -15,6 +15,11 @@ import type { RegisterManagementAppArgs } from 'src/plugins/management/public'; import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; import type { SecurityLicense } from '../../../common/licensing'; +import { + Breadcrumb, + BreadcrumbsProvider, + createBreadcrumbsChangeHandler, +} from '../../components/breadcrumb'; import type { PluginStartDependencies } from '../../plugin'; import { tryDecodeURIComponent } from '../url_utils'; @@ -35,13 +40,6 @@ export const rolesManagementApp = Object.freeze({ order: 20, title, async mount({ element, setBreadcrumbs, history }) { - const rolesBreadcrumbs = [ - { - text: title, - href: `/`, - }, - ]; - const [ [startServices, { data, features, spaces }], { RolesGridPage }, @@ -72,16 +70,6 @@ export const rolesManagementApp = Object.freeze({ chrome.docTitle.change(title); const rolesAPIClient = new RolesAPIClient(http); - const RolesGridPageWithBreadcrumbs = () => { - setBreadcrumbs(rolesBreadcrumbs); - return ( - - ); - }; const EditRolePageWithBreadcrumbs = ({ action }: { action: 'edit' | 'clone' }) => { const { roleName } = useParams<{ roleName?: string }>(); @@ -90,38 +78,38 @@ export const rolesManagementApp = Object.freeze({ // See https://github.com/elastic/kibana/issues/82440 const decodedRoleName = roleName ? tryDecodeURIComponent(roleName) : undefined; - setBreadcrumbs([ - ...rolesBreadcrumbs, - action === 'edit' && roleName + const breadcrumbObj = + action === 'edit' && roleName && decodedRoleName ? { text: decodedRoleName, href: `/edit/${encodeURIComponent(roleName)}` } : { text: i18n.translate('xpack.security.roles.createBreadcrumb', { defaultMessage: 'Create', }), - }, - ]); + }; const spacesApiUi = spaces?.ui; return ( - + + + ); }; @@ -129,26 +117,32 @@ export const rolesManagementApp = Object.freeze({ - - - - - - - - - - - + + + + + + + + + + + + + , - element ); return () => { - chrome.docTitle.reset(); unmountComponentAtNode(element); }; }, diff --git a/x-pack/plugins/security/public/management/users/users_management_app.test.tsx b/x-pack/plugins/security/public/management/users/users_management_app.test.tsx index f4fed153d9975..f25fb211cb9de 100644 --- a/x-pack/plugins/security/public/management/users/users_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/users/users_management_app.test.tsx @@ -5,7 +5,11 @@ * 2.0. */ +import { act } from '@testing-library/react'; +import { noop } from 'lodash'; + import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; +import type { Unmount } from 'src/plugins/management/public/types'; import { securityMock } from '../../mocks'; import { usersManagementApp } from './users_management_app'; @@ -22,16 +26,19 @@ describe('usersManagementApp', () => { const setBreadcrumbs = jest.fn(); const history = scopedHistoryMock.create({ pathname: '/create' }); - const unmount = await usersManagementApp.create({ authc, getStartServices }).mount({ - basePath: '/', - element, - setBreadcrumbs, - history, + let unmount: Unmount = noop; + await act(async () => { + unmount = await usersManagementApp.create({ authc, getStartServices }).mount({ + basePath: '/', + element, + setBreadcrumbs, + history, + }); }); expect(setBreadcrumbs).toHaveBeenLastCalledWith([ { href: '/', text: 'Users' }, - { href: '/create', text: 'Create' }, + { text: 'Create' }, ]); unmount(); diff --git a/x-pack/plugins/security/public/management/users/users_management_app.tsx b/x-pack/plugins/security/public/management/users/users_management_app.tsx index f6a2956c7ad43..7957599da7f57 100644 --- a/x-pack/plugins/security/public/management/users/users_management_app.tsx +++ b/x-pack/plugins/security/public/management/users/users_management_app.tsx @@ -119,7 +119,6 @@ export const usersManagementApp = Object.freeze({ ); return () => { - coreStart.chrome.docTitle.reset(); unmountComponentAtNode(element); }; }, diff --git a/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx b/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx index 0b6df121cb166..aefff7fb3c76a 100644 --- a/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx +++ b/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx @@ -77,7 +77,7 @@ describe('spacesManagementApp', () => { const { setBreadcrumbs, container, unmount, docTitle } = await mountApp('/', '/'); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); - expect(setBreadcrumbs).toHaveBeenCalledWith([{ href: `/`, text: 'Spaces' }]); + expect(setBreadcrumbs).toHaveBeenCalledWith([{ text: 'Spaces' }]); expect(docTitle.change).toHaveBeenCalledWith('Spaces'); expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(` @@ -102,7 +102,7 @@ describe('spacesManagementApp', () => { expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([ { href: `/`, text: 'Spaces' }, - { href: '/create', text: 'Create' }, + { text: 'Create' }, ]); expect(docTitle.change).toHaveBeenCalledWith('Spaces'); expect(docTitle.reset).not.toHaveBeenCalled(); @@ -134,7 +134,7 @@ describe('spacesManagementApp', () => { expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([ { href: `/`, text: 'Spaces' }, - { href: `/edit/${spaceId}`, text: `space with id some-space` }, + { text: `space with id some-space` }, ]); expect(docTitle.change).toHaveBeenCalledWith('Spaces'); expect(docTitle.reset).not.toHaveBeenCalled(); diff --git a/x-pack/plugins/spaces/public/management/spaces_management_app.tsx b/x-pack/plugins/spaces/public/management/spaces_management_app.tsx index 5d44a1cd78635..8ea947a33037d 100644 --- a/x-pack/plugins/spaces/public/management/spaces_management_app.tsx +++ b/x-pack/plugins/spaces/public/management/spaces_management_app.tsx @@ -43,18 +43,16 @@ export const spacesManagementApp = Object.freeze({ const [[coreStart, { features }], { SpacesGridPage }, { ManageSpacePage }] = await Promise.all([getStartServices(), import('./spaces_grid'), import('./edit_space')]); - const spacesBreadcrumbs = [ - { - text: title, - href: `/`, - }, - ]; + const spacesFirstBreadcrumb = { + text: title, + href: `/`, + }; const { notifications, i18n: i18nStart, application, chrome } = coreStart; chrome.docTitle.change(title); const SpacesGridPageWithBreadcrumbs = () => { - setBreadcrumbs(spacesBreadcrumbs); + setBreadcrumbs([{ ...spacesFirstBreadcrumb, href: undefined }]); return ( { setBreadcrumbs([ - ...spacesBreadcrumbs, + spacesFirstBreadcrumb, { text: i18n.translate('xpack.spaces.management.createSpaceBreadcrumb', { defaultMessage: 'Create', }), - href: '/create', }, ]); @@ -94,10 +91,9 @@ export const spacesManagementApp = Object.freeze({ const onLoadSpace = (space: Space) => { setBreadcrumbs([ - ...spacesBreadcrumbs, + spacesFirstBreadcrumb, { text: space.name, - href: `/edit/${encodeURIComponent(space.id)}`, }, ]); }; diff --git a/x-pack/test/accessibility/apps/users.ts b/x-pack/test/accessibility/apps/users.ts index bafd608aa8dee..8682cc8f0a884 100644 --- a/x-pack/test/accessibility/apps/users.ts +++ b/x-pack/test/accessibility/apps/users.ts @@ -88,11 +88,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('a11y test for edit user panel', async () => { + await PageObjects.settings.clickLinkText('Users'); await PageObjects.settings.clickLinkText('deleteA11y'); await a11y.testAppSnapshot(); }); it('a11y test for change password screen', async () => { + await PageObjects.settings.clickLinkText('Users'); await PageObjects.settings.clickLinkText('deleteA11y'); await find.clickByButtonText('Change password'); await a11y.testAppSnapshot(); @@ -100,6 +102,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('a11y test for deactivate user screen', async () => { + await PageObjects.settings.clickLinkText('Users'); await PageObjects.settings.clickLinkText('deleteA11y'); await find.clickByButtonText('Deactivate user'); await a11y.testAppSnapshot(); From b2e2264a2f440fb5f89197c956cfe07941038ad5 Mon Sep 17 00:00:00 2001 From: Diana Derevyankina <54894989+DziyanaDzeraviankina@users.noreply.github.com> Date: Thu, 11 Nov 2021 16:46:29 +0300 Subject: [PATCH 50/51] [TSVB] Filter with scripted field doesn't work after migration to 7.13.1 (#115762) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../timeseries/server/lib/vis_data/get_series_data.ts | 5 ++++- .../timeseries/server/lib/vis_data/get_table_data.ts | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/get_series_data.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_series_data.ts index a9a3825f5a9df..6f96c0d23cad7 100644 --- a/src/plugins/vis_types/timeseries/server/lib/vis_data/get_series_data.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_series_data.ts @@ -36,7 +36,10 @@ export async function getSeriesData( fieldFormatService, } = services; - const panelIndex = await cachedIndexPatternFetcher(panel.index_pattern); + const panelIndex = await cachedIndexPatternFetcher( + panel.index_pattern, + !panel.use_kibana_indexes + ); const strategy = await searchStrategyRegistry.getViableStrategy(requestContext, req, panelIndex); diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/get_table_data.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_table_data.ts index 3b53147dc6f93..35b6a78d0579b 100644 --- a/src/plugins/vis_types/timeseries/server/lib/vis_data/get_table_data.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_table_data.ts @@ -31,7 +31,10 @@ export async function getTableData( panel: Panel, services: VisTypeTimeseriesRequestServices ) { - const panelIndex = await services.cachedIndexPatternFetcher(panel.index_pattern); + const panelIndex = await services.cachedIndexPatternFetcher( + panel.index_pattern, + !panel.use_kibana_indexes + ); const strategy = await services.searchStrategyRegistry.getViableStrategy( requestContext, From 477cb3bb15dd0ffa9be8db6c5918cb7f9bec0b29 Mon Sep 17 00:00:00 2001 From: Kristof C Date: Thu, 11 Nov 2021 07:56:30 -0600 Subject: [PATCH 51/51] [Timeline] [117942] Fix autofocus jumping to wrong field (#117950) * Fix autofocus jumping to wrong field * Fix Timeline cypress test to reflect focus being on correct field Co-authored-by: Kristof-Pierre Cummings Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../cypress/screens/timeline.ts | 2 + .../cypress/tasks/timeline.ts | 6 +- .../components/edit_data_provider/index.tsx | 158 +++++++++--------- 3 files changed, 83 insertions(+), 83 deletions(-) diff --git a/x-pack/plugins/security_solution/cypress/screens/timeline.ts b/x-pack/plugins/security_solution/cypress/screens/timeline.ts index 619e7d01f10e2..81e025fa6db8f 100644 --- a/x-pack/plugins/security_solution/cypress/screens/timeline.ts +++ b/x-pack/plugins/security_solution/cypress/screens/timeline.ts @@ -149,6 +149,8 @@ export const TIMELINE_ADD_FIELD_BUTTON = '[data-test-subj="addField"]'; export const TIMELINE_DATA_PROVIDER_FIELD = '[data-test-subj="field"]'; +export const TIMELINE_DATA_PROVIDER_FIELD_INPUT = '[data-test-subj="comboBoxSearchInput"]'; + export const TIMELINE_DATA_PROVIDER_OPERATOR = `[data-test-subj="operator"]`; export const TIMELINE_DATA_PROVIDER_VALUE = `[data-test-subj="value"]`; diff --git a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts b/x-pack/plugins/security_solution/cypress/tasks/timeline.ts index 01a3b6f18be80..03b931bc74d77 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/timeline.ts @@ -69,6 +69,7 @@ import { TIMELINE_TAB_CONTENT_EQL, TIMESTAMP_HOVER_ACTION_OVERFLOW_BTN, PINNED_TAB_BUTTON, + TIMELINE_DATA_PROVIDER_FIELD_INPUT, } from '../screens/timeline'; import { REFRESH_BUTTON, TIMELINE } from '../screens/timelines'; @@ -176,8 +177,9 @@ export const addFilter = (filter: TimelineFilter): Cypress.Chainable> => { cy.get(TIMELINE_ADD_FIELD_BUTTON).click(); cy.get(LOADING_INDICATOR).should('not.exist'); - cy.get(TIMELINE_DATA_PROVIDER_VALUE).should('have.focus'); // make sure the focus is ready before start typing - + cy.get(TIMELINE_DATA_PROVIDER_FIELD) + .find(TIMELINE_DATA_PROVIDER_FIELD_INPUT) + .should('have.focus'); // make sure the focus is ready before start typing cy.get(TIMELINE_DATA_PROVIDER_FIELD) .find(COMBO_BOX_INPUT) .type(`${filter.field}{downarrow}{enter}`); diff --git a/x-pack/plugins/security_solution/public/timelines/components/edit_data_provider/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/edit_data_provider/index.tsx index 2fd9a1de1b8bc..dcf32cb585f9e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/edit_data_provider/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/edit_data_provider/index.tsx @@ -13,7 +13,6 @@ import { EuiFieldText, EuiFlexGroup, EuiFlexItem, - EuiFocusTrap, EuiFormRow, EuiPanel, EuiSpacer, @@ -181,7 +180,6 @@ export const StatefulEditDataProvider = React.memo( useEffect(() => { disableScrolling(); - focusInput(); return () => { enableScrolling(); }; @@ -189,94 +187,92 @@ export const StatefulEditDataProvider = React.memo( return ( - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - {type !== DataProviderType.template && - updatedOperator.length > 0 && - updatedOperator[0].label !== i18n.EXISTS && - updatedOperator[0].label !== i18n.DOES_NOT_EXIST ? ( - - + - ) : null} + + - - - + + + + {type !== DataProviderType.template && + updatedOperator.length > 0 && + updatedOperator[0].label !== i18n.EXISTS && + updatedOperator[0].label !== i18n.DOES_NOT_EXIST ? ( - - - - {i18n.SAVE} - - - + + + - - + ) : null} + + + + + + + + + + {i18n.SAVE} + + + + + ); }