From b59af8b63789fc0359a67d8a1aaadce62dec6b4d Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Wed, 9 Aug 2023 08:04:34 -0400 Subject: [PATCH 01/22] fix(slo): Active alert query (#163404) --- .../slo_active_alerts_badge.stories.tsx | 2 +- .../hooks/slo/use_fetch_active_alerts.ts | 19 +++++++++---------- .../pages/slos/components/slo_summary.tsx | 6 +++++- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_active_alerts_badge.stories.tsx b/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_active_alerts_badge.stories.tsx index 08fa152301d43..3aed4658ab766 100644 --- a/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_active_alerts_badge.stories.tsx +++ b/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_active_alerts_badge.stories.tsx @@ -25,4 +25,4 @@ const Template: ComponentStory = (props: Props) => ( ); export const Default = Template.bind({}); -Default.args = { activeAlerts: { count: 2, ruleIds: ['rule-1', 'rule-2'] } }; +Default.args = { activeAlerts: { count: 2 } }; diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts index 319f3e57a4a4c..580d72e550e6b 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts @@ -19,7 +19,6 @@ interface Params { export interface ActiveAlerts { count: number; - ruleIds: string[]; } type ActiveAlertsMap = Record; @@ -37,7 +36,6 @@ interface FindApiResponse { buckets: Array<{ key: string; doc_count: number; - perRuleId: { buckets: Array<{ key: string; doc_count: number }> }; }>; }; }; @@ -77,20 +75,22 @@ export function useFetchActiveAlerts({ sloIds = [] }: Params): UseFetchActiveAle }, }, ], + should: [ + { + terms: { + 'kibana.alert.rule.parameters.sloId': sloIds, + }, + }, + ], + minimum_should_match: 1, }, }, aggs: { perSloId: { terms: { + size: sloIds.length, field: 'kibana.alert.rule.parameters.sloId', }, - aggs: { - perRuleId: { - terms: { - field: 'kibana.alert.rule.uuid', - }, - }, - }, }, }, }), @@ -102,7 +102,6 @@ export function useFetchActiveAlerts({ sloIds = [] }: Params): UseFetchActiveAle ...acc, [bucket.key]: { count: bucket.doc_count ?? 0, - ruleIds: bucket.perRuleId.buckets.map((rule) => rule.key), } as ActiveAlerts, }), {} diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_summary.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_summary.tsx index 491eb2e8bc09c..f2a6fce036ebe 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/slo_summary.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/slo_summary.tsx @@ -87,7 +87,11 @@ export function SloSummary({ slo, historicalSummary = [], historicalSummaryLoadi defaultMessage: 'Budget remaining', })} textAlign="right" - title={numeral(errorBudgetRemaining).format(percentFormat)} + title={ + slo.summary.status === 'NO_DATA' + ? NOT_AVAILABLE_LABEL + : numeral(errorBudgetRemaining).format(percentFormat) + } titleColor={titleColor} titleSize="m" reverse From 21b33e4342ba6161b5cb8dd6dd492c07aa857c7f Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 9 Aug 2023 13:45:11 +0100 Subject: [PATCH 02/22] skip failing es promotion suites (#163486) --- .../api_integration/apis/metrics_ui/log_entry_highlights.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/api_integration/apis/metrics_ui/log_entry_highlights.ts b/x-pack/test/api_integration/apis/metrics_ui/log_entry_highlights.ts index fd87af88ebc8b..f1be3edf0f4ac 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/log_entry_highlights.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/log_entry_highlights.ts @@ -45,7 +45,8 @@ export default function ({ getService }: FtrProviderContext) { after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/simple_logs')); describe('/log_entries/highlights', () => { - describe('with the default source', () => { + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/163486 + describe.skip('with the default source', () => { before(() => kibanaServer.savedObjects.cleanStandardList()); after(() => kibanaServer.savedObjects.cleanStandardList()); From fd2815234875a3e432993b2da4c2fdb1796e7625 Mon Sep 17 00:00:00 2001 From: Hannah Mudge Date: Wed, 9 Aug 2023 08:24:03 -0600 Subject: [PATCH 03/22] [Dashboard] Unskip failing `embed_mode` screenshot test (#163424) Closes https://github.com/elastic/kibana/issues/163207 ## Summary Since Chrome was updated in the CI environment, our old CI-generated screenshots were outdated - this PR updates the `embed_mode` screenshot tests so that we are once again in sync with the CI environment. For more context, please refer to https://github.com/elastic/kibana/pull/160085 ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- .../apps/dashboard/group5/embed_mode.ts | 3 +-- .../baseline/dashboard_embed_mode.png | Bin 131944 -> 129613 bytes .../dashboard_embed_mode_scrolling.png | Bin 92543 -> 92765 bytes .../dashboard_embed_mode_with_url_params.png | Bin 142900 -> 140548 bytes 4 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/functional/apps/dashboard/group5/embed_mode.ts b/test/functional/apps/dashboard/group5/embed_mode.ts index 2599326daba43..16934fc9101a8 100644 --- a/test/functional/apps/dashboard/group5/embed_mode.ts +++ b/test/functional/apps/dashboard/group5/embed_mode.ts @@ -24,8 +24,7 @@ export default function ({ const screenshot = getService('screenshots'); const log = getService('log'); - // Failing: See https://github.com/elastic/kibana/issues/163207 - describe.skip('embed mode', () => { + describe('embed mode', () => { /* * Note: The baseline images used in all of the screenshot tests in this test suite were taken directly from the CI environment * in order to overcome a known issue with the pixel density of fonts being significantly different when running locally versus diff --git a/test/functional/screenshots/baseline/dashboard_embed_mode.png b/test/functional/screenshots/baseline/dashboard_embed_mode.png index 0c6b37523367931aec8b5d1819be339c9ab72f54..592cd6c4ff4036976b571165fcda8938f93f9d6d 100644 GIT binary patch literal 129613 zcmce-Wmr^g_Xj$NfJ%w9l(Zn-jY@}rG*U`;*U*U4Aq@fp0@B?h-93naLpKcFJ;d4g zK9BGJy{>bek7s{TX74-Jx>x?zxiRPokdeX@Xf@Q@eva;f)l-JkK6p>+HsI$ki!^OJU2{9neNPrczs3T8CN)ZCcUIhj&Vh+*z?PFHRKTmJM%9X3O(el!vC?6l2*clXEVsT9+ zLL^4k(~QV08!v9szfHy8^nKX+*aktN`YGG#mH;`9jV6X>0|hQWX5096*!5SMe;;~w z_c!dUqN4M(qrXPkCNwiY8mY>okL1N2oK`OEZAFb}b9G6AlyNZ)Ac;?)i5-ircJ5zN zOqW|nND4Jh+u+kplBKNwPNqspV9|RNI@))BQNOro*KNX;sLffCLyCp2$UqCBB)amR z2@y(BpP~-^mza2_B$nsW()3Hqrfo)?36dhFL0v}e@Se!t{LWuEf4Q48Sa0%*v%{*( zsF@3HSCJfIrDpp{>CbnC|9&b98T?N1(oy?TS0MF9xT`szE~-0MRrqH(1Ftu< z)=|UGmP~bO@xKJ<5*B8XWPI&gQFg1m$ynE$K9gdsU>6Ea5RR_0(jwTK`5gvguTu?E z{Z~?Qt_nFMAj@jp8=}@nXkDF0CAW-U#j0w*#Fvhz{-yX)Q9A)a9_wv*NPRVC?JY;m zG}?6gvMSi5Yn~o2@$Y6ot5QD-Gu#n@@%zcFLd(GAevs*wbM9DPzl`Uw@_(0Ej}W;a`|+_TG+rt^ski0gbjX2lhPu7gvl(z zcTx!x_Dn(iC0Vb4xs!RAlPN{8%+D{2_*;Mh^i-yW^EtxR!-jds;0DECt&fx*KlAS< z(cZG4bu|Ww5%;JdY)%T#_uWnIy;Q2;&^;y#%s>5E=nXq!OZ52fW($p&o+lpvL=f>_ zJ3R{fEX1CHru+9TojsvZ0)jJr^ZoM`LG<^EJyTtHQGb{EtWk{CRm<+9Je}0c4pRXA zWTx}yOh079VaPFEh5G0repF*U{2$Jw8R^G=rwbOlwSTGBJnt22d;mq**_^lRu?f^_ z`ZFpY+v}-*`%Akz387Ihw|{hS3KiwHbOysXo2TAvbZmFV9#h1pvM)BT+`HyP7O#Xo})#TOz8k)@+%LJjW=88K;n&q3hs z4NMX9HBn<5?kGU6UE*frhCyjZRBEM{JyFK=cZNBF{LEz5de1)GTkO&`!zK8C?Rq1j zMQ_z#8Xx3mKL2+V&F9Sjn$r-1AO-Kej! z<%^ZCl+gT4rV=ml=f4xunCg4Jdlv(Pe=+~}H1L=>2nqfwdQPjl%6~U~kDGYaB)DU- zP~eWOooHC-5*5`&jmp3uIW|nCjb+asX{d;Z$EX|K@j$g!-!7}*KX1L6`tBJAJOcPl ztM$aPZaP8z&c?;RMGr*D9ucgH1S~heR)IG4ImWw@z6A7pFT%o!2!`K0x8>7?Z8_Jy zXuI176Io@POkkV;tlco!mMeuV*Ue~M+be+dy|0_DnBGZ#BRyz_ zZx;73yW+Up@=io$Z?@eqG*hvQ#)HP!6gjFg^g2Fwe2720)1Y`|oZvtf>$W2?t-h*E z58u}haYRH}vySnFkP*Xx6}>1eX6jJDh{d2BM^&7{s?QxuSCiV_ zw+^Y6Hx4I6Anbc7`(s57qh{@TMrYs1eZN~>(1bJfz{PzaVfxkXx50ko9T)ps!dHDt z-Cn)IgE1uVrLvmW|Iwv*W!SfY?ldSKFuTfsm=dGMvgiC=53S1?G2GXj-<8EU_Gi`f zE+ZHdB}BMW2b^)YN|%%GocnGsffh6~GkItG(~PJ5oexx
    #)ye8M^&|7sV2JkE< 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 z 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 literal 131944 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

    |IQcC~~4SpP{B!(u0tz#9Hc+SoD!yF+=e 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⁢X_d&AjzR5)!qRd?B--D8dHZj#u2nfR>5ek> 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

    xZpDZ1gml`i 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 diff --git a/test/functional/screenshots/baseline/dashboard_embed_mode_with_url_params.png b/test/functional/screenshots/baseline/dashboard_embed_mode_with_url_params.png index cbf96cdbf278b4221d88b02bab0d78e9731d69f7..26a18ede2d686fefdf1fa2382819591e4c79558b 100644 GIT binary patch literal 140548 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�uttfpQ6%U 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 B{wn|g From db0996f4a3f3a882347384e9f24de7e560f4d0eb Mon Sep 17 00:00:00 2001 From: Marshall Main <55718608+marshallmain@users.noreply.github.com> Date: Wed, 9 Aug 2023 07:26:08 -0700 Subject: [PATCH 04/22] [Security Solution] Move remaining timeline route schemas to /common/api (#162857) Closes https://github.com/elastic/security-team/issues/7099 Follow up to https://github.com/elastic/kibana/pull/162314 I mislabeled 3 timeline-related internal APIs as detection engine APIs on [this spreadsheet](https://docs.google.com/spreadsheets/d/1VCoJ74EkyGuj59VwWj_3v2ecB84pNCpzGqkYnS0SUKw/edit?pli=1#gid=1102015677) (create_tags, get_tags_by_name, get_dashboards_by_tags). The APIs are now correctly categorized on the spreadsheet and this PR establishes schemas for them in `/common/api`. I also converted these 3 small schemas to io-ts to make it easier to avoid pulling in `@kbn/config-schema` to `public`, as that increased the async chunk size by a full 840KB. --- .github/CODEOWNERS | 1 + .../api/tags/create_tag/create_tag_route.ts | 15 +++++++++++++++ .../get_dashboards_by_tags_route.ts | 10 ++++++++++ .../get_tags_by_name/get_tags_by_name_route.ts | 10 ++++++++++ .../security_solution/common/api/tags/index.ts | 10 ++++++++++ .../dashboards/routes/get_dashboards_by_tags.ts | 9 +++------ .../server/lib/tags/routes/create_tag.ts | 11 +++-------- .../server/lib/tags/routes/get_tags_by_name.ts | 9 +++------ 8 files changed, 55 insertions(+), 20 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/api/tags/create_tag/create_tag_route.ts create mode 100644 x-pack/plugins/security_solution/common/api/tags/get_dashboards_by_tags/get_dashboards_by_tags_route.ts create mode 100644 x-pack/plugins/security_solution/common/api/tags/get_tags_by_name/get_tags_by_name_route.ts create mode 100644 x-pack/plugins/security_solution/common/api/tags/index.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index dfcda878c2e4e..06e0d2478429f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1098,6 +1098,7 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib /x-pack/plugins/security_solution/server/lib/timeline @elastic/security-threat-hunting-investigations ## Security Solution sub teams - Threat Hunting Explore +/x-pack/plugins/security_solution/common/api/tags @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/common/api/risk_score @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/common/search_strategy/security_solution/matrix_histogram @elastic/security-threat-hunting-explore diff --git a/x-pack/plugins/security_solution/common/api/tags/create_tag/create_tag_route.ts b/x-pack/plugins/security_solution/common/api/tags/create_tag/create_tag_route.ts new file mode 100644 index 0000000000000..160ae43b9aa0f --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/tags/create_tag/create_tag_route.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import * as rt from 'io-ts'; + +export const createTagRequest = rt.intersection([ + rt.type({ + name: rt.string, + description: rt.string, + }), + rt.partial({ color: rt.string }), +]); diff --git a/x-pack/plugins/security_solution/common/api/tags/get_dashboards_by_tags/get_dashboards_by_tags_route.ts b/x-pack/plugins/security_solution/common/api/tags/get_dashboards_by_tags/get_dashboards_by_tags_route.ts new file mode 100644 index 0000000000000..af2c89a967311 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/tags/get_dashboards_by_tags/get_dashboards_by_tags_route.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as rt from 'io-ts'; + +export const getDashboardsRequest = rt.type({ tagIds: rt.array(rt.string) }); diff --git a/x-pack/plugins/security_solution/common/api/tags/get_tags_by_name/get_tags_by_name_route.ts b/x-pack/plugins/security_solution/common/api/tags/get_tags_by_name/get_tags_by_name_route.ts new file mode 100644 index 0000000000000..4ae16c320c02e --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/tags/get_tags_by_name/get_tags_by_name_route.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as rt from 'io-ts'; + +export const getTagsByNameRequest = rt.type({ name: rt.string }); diff --git a/x-pack/plugins/security_solution/common/api/tags/index.ts b/x-pack/plugins/security_solution/common/api/tags/index.ts new file mode 100644 index 0000000000000..3f48011365f42 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/tags/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './create_tag/create_tag_route'; +export * from './get_dashboards_by_tags/get_dashboards_by_tags_route'; +export * from './get_tags_by_name/get_tags_by_name_route'; diff --git a/x-pack/plugins/security_solution/server/lib/dashboards/routes/get_dashboards_by_tags.ts b/x-pack/plugins/security_solution/server/lib/dashboards/routes/get_dashboards_by_tags.ts index 7e0f8bfdaa4ce..356e4c1996e24 100644 --- a/x-pack/plugins/security_solution/server/lib/dashboards/routes/get_dashboards_by_tags.ts +++ b/x-pack/plugins/security_solution/server/lib/dashboards/routes/get_dashboards_by_tags.ts @@ -6,7 +6,6 @@ */ import type { Logger } from '@kbn/core/server'; import { i18n } from '@kbn/i18n'; -import { schema } from '@kbn/config-schema'; import type { DashboardAttributes } from '@kbn/dashboard-plugin/common'; import { transformError } from '@kbn/securitysolution-es-utils'; @@ -15,10 +14,8 @@ import type { SetupPlugins } from '../../../plugin'; import type { SecuritySolutionPluginRouter } from '../../../types'; import { buildSiemResponse } from '../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../timeline/utils/common'; - -const getDashboardsParamsSchema = schema.object({ - tagIds: schema.arrayOf(schema.string()), -}); +import { getDashboardsRequest } from '../../../../common/api/tags'; +import { buildRouteValidationWithExcess } from '../../../utils/build_validation/route_validation'; export const getDashboardsByTagsRoute = ( router: SecuritySolutionPluginRouter, @@ -28,7 +25,7 @@ export const getDashboardsByTagsRoute = ( router.post( { path: INTERNAL_DASHBOARDS_URL, - validate: { body: getDashboardsParamsSchema }, + validate: { body: buildRouteValidationWithExcess(getDashboardsRequest) }, options: { tags: ['access:securitySolution'], }, diff --git a/x-pack/plugins/security_solution/server/lib/tags/routes/create_tag.ts b/x-pack/plugins/security_solution/server/lib/tags/routes/create_tag.ts index 4eaed27813214..6ddc14d64d53f 100644 --- a/x-pack/plugins/security_solution/server/lib/tags/routes/create_tag.ts +++ b/x-pack/plugins/security_solution/server/lib/tags/routes/create_tag.ts @@ -6,22 +6,17 @@ */ import type { Logger } from '@kbn/core/server'; import { i18n } from '@kbn/i18n'; -import { schema } from '@kbn/config-schema'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { createTagRequest } from '../../../../common/api/tags'; import { INTERNAL_TAGS_URL } from '../../../../common/constants'; import type { SetupPlugins } from '../../../plugin'; import type { SecuritySolutionPluginRouter } from '../../../types'; +import { buildRouteValidationWithExcess } from '../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../timeline/utils/common'; import { createTag } from '../saved_objects'; -const createTagBodySchema = schema.object({ - name: schema.string(), - description: schema.string(), - color: schema.maybe(schema.string()), -}); - export const createTagRoute = ( router: SecuritySolutionPluginRouter, logger: Logger, @@ -30,7 +25,7 @@ export const createTagRoute = ( router.put( { path: INTERNAL_TAGS_URL, - validate: { body: createTagBodySchema }, + validate: { body: buildRouteValidationWithExcess(createTagRequest) }, options: { tags: ['access:securitySolution'], }, diff --git a/x-pack/plugins/security_solution/server/lib/tags/routes/get_tags_by_name.ts b/x-pack/plugins/security_solution/server/lib/tags/routes/get_tags_by_name.ts index 05d20d90e09b2..a88578365f037 100644 --- a/x-pack/plugins/security_solution/server/lib/tags/routes/get_tags_by_name.ts +++ b/x-pack/plugins/security_solution/server/lib/tags/routes/get_tags_by_name.ts @@ -6,20 +6,17 @@ */ import type { Logger } from '@kbn/core/server'; import { i18n } from '@kbn/i18n'; -import { schema } from '@kbn/config-schema'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { getTagsByNameRequest } from '../../../../common/api/tags'; import { INTERNAL_TAGS_URL } from '../../../../common/constants'; import type { SetupPlugins } from '../../../plugin'; import type { SecuritySolutionPluginRouter } from '../../../types'; +import { buildRouteValidationWithExcess } from '../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../timeline/utils/common'; import { findTagsByName } from '../saved_objects'; -const getTagsParamsSchema = schema.object({ - name: schema.string(), -}); - export const getTagsByNameRoute = ( router: SecuritySolutionPluginRouter, logger: Logger, @@ -28,7 +25,7 @@ export const getTagsByNameRoute = ( router.get( { path: INTERNAL_TAGS_URL, - validate: { query: getTagsParamsSchema }, + validate: { query: buildRouteValidationWithExcess(getTagsByNameRequest) }, options: { tags: ['access:securitySolution'], }, From f48d422a2e5114e899df5697a18de10918beb779 Mon Sep 17 00:00:00 2001 From: Wafaa Nasr Date: Wed, 9 Aug 2023 16:40:55 +0200 Subject: [PATCH 05/22] [Security Solution] [Flaky test] Fix double ftr test flakiness (#162990) ## Summary - Addresses https://github.com/elastic/kibana/issues/155122 ## Investigations *First attempt* > While investigating the three failing pipelines and examining the Artifacts, specifically target/test_failures/*.log, I discovered the root cause to be > Did not get an expected 200 "ok" when waiting for a list item (waitForListItem) yet. Retrying until we get a 200 "ok". body: {"message":"list_id: \"list_items.txt\" item of 1.0 does not exist","status_code":404}, status: 404 > > ![image](https://github.com/elastic/kibana/assets/12671903/ad3c4db9-e340-42c0-8a61-63e5387b9b83) > *Second attempt* > Upon incorporating additional logs to pinpoint the underlying issue, it was realized that the test will persist in its attempts until the preceding error is rectified, and it was determined that the list_items.txt file contains the correct item once located. > > The problem seemed to be associated with incomplete indexing of all indices signalsOpen.hits.hits when the test verifies against the anticipated value. > > To investigate the matter, two iterations were conducted, totaling 490 attempts. During these iterations, logs, and warnings were deliberately inserted to facilitate the tracing of the issue. > > https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2770#0189bb29-c258-4586-986a-2ac5e128eb52 > https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2768#0189baeb-8f09-488e-936f-69e72d089787 > > In this [Atifact](https://s3.amazonaws.com/buildkiteartifacts.com/e0f3970e-3a75-4621-919f-e6c773e2bb12/fedcad1e-0f36-4d55-bdc7-e1edbecf91fe/0189bb29-495f-4b7e-b34e-558ff6c02ce2/0189bb29-c258-4586-986a-2ac5e128eb52/target/test_failures/0189bb29-c258-4586-986a-2ac5e128eb52_d98d35afa0abd1ad03e28a68882291c4.log?response-content-type=text%2Fplain&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAQPCP3C7LXS7MSJGH%2F20230808%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20230808T102039Z&X-Amz-Expires=600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEOH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJHMEUCIQDYG9De6RYDlVNcO0JGqO6Qc4dpzCQG1s%2BgaXTSimWc9QIgfkZgXlnVcScJCO56vz2VQx1buVTNEDEaVYhYmDgupEgq%2BgMIiv%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgwwMzIzNzk3MDUzMDMiDOz2Gl2kfcuTHVaWyirOA4iHfkFBI7KBoy%2F97CuLMAxGLNIR8h4FtLCsY664lMhgDGd%2FBVi82zu%2B2Y5DAGEboOmb7C1q%2FX6CyesjDKP7sknXdfT7q8B4jBRK4QcVw2AAvC9%2BqMeN37eCfRXWT%2FrQAEdaWzxkJxk4BtFcATds3LJmmAlbYOT2L7vItmGzGs%2FnkRYevX%2Fq6hwxWqmOKNNot9hZ9sMJ3TZvGsA3045459BfyfObwIlzb13Pj6V7%2FMyTb87RjQazFiK%2Bb7qOXB%2B7ItaVAcpG7diXzPAif%2F%2FEiJedTHtBVh4LsMIKQtiASbcTh4X90kYtVMUcH%2BSG0B41WjWYPok0C3tHfQnGhGBIbSnqvMGmWgwGlhHNF1G7nIDYyWs32PQ3M3WmTGQuLIwp2hPzk4wFtgH%2FDQPWevRFRT%2FhzYJf05hyBT9BMcST9eeKTqEqs52PhCHDlCgo7K5bGjT86OO16MzEKdA77HRro8GqIh6mgTMyQ5gKpH38ueUWvQZnLix4T5HYw0EyJgRLRfiVIpKcH0jRobaFwKSfSYc%2FZ2FPHsAK31weedhy6tafwU7elNYiAaMRv4AQhB%2FlrGWYd6IjOrdgSFowlkd1m5%2FrYTY3k7%2F8D0vsxgjUETDX9semBjqlAWkLq%2FLaRV5KokMNXfT3lCVNJzpYeN1%2FdnInE%2BQn3Ub86kRgMOfTN2OgDHkuYSKsQ95tFHH49NfRn6rTw8tI2Tjs3pToqp65gCYh9MzUKTd2EWsgqdNn6y%2BbHRGFJxd7cacrX9Ghr4XyNme5aAeWAVYNXSqJ1KIbtWmRcwwhThAJHxWk5%2FoBwScZRUSYGWmkhaxnZXDjXg6LBuH7uZOJjf%2FLuFVdtQ%3D%3D&X-Amz-SignedHeaders=host&X-Amz-Signature=8a44c3a5e3b88b632097dc344ecec1ba6d6cb8e80e10d9058e96883e43d925b5) > > ![image](https://github.com/elastic/kibana/assets/12671903/bc58d389-3586-4343-a9f9-9577331d4876) > > ## Solution By modifying the third parameter of the `await waitForSignalsToBePresent(supertest, log, 1, [id]);` function to a value of 3 instead of the initial 1, we signify the number of alerts we need to await before conducting assertions. This change is made to accommodate the assertion of three alerts being generated, accounting for the exclusion of a single 1.0 value. --- .../group7/exception_operators_data_types/double.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group7/exception_operators_data_types/double.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group7/exception_operators_data_types/double.ts index 05d821b5932fb..39a878a82f896 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group7/exception_operators_data_types/double.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group7/exception_operators_data_types/double.ts @@ -33,8 +33,7 @@ export default ({ getService }: FtrProviderContext) => { const log = getService('log'); const es = getService('es'); - // Failing: See https://github.com/elastic/kibana/issues/155122 - describe.skip('Rule exception operators for data type double', () => { + describe('Rule exception operators for data type double', () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/rule_exceptions/double'); await esArchiver.load('x-pack/test/functional/es_archives/rule_exceptions/double_as_string'); @@ -490,7 +489,6 @@ export default ({ getService }: FtrProviderContext) => { expect(hits).to.eql([]); }); }); - describe('working against string values in the data set', () => { it('will return 3 results if we have a list that includes 1 double', async () => { await importFile(supertest, log, 'double', ['1.0'], 'list_items.txt'); @@ -509,7 +507,7 @@ export default ({ getService }: FtrProviderContext) => { ], ]); await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 1, [id]); + await waitForSignalsToBePresent(supertest, log, 3, [id]); const signalsOpen = await getSignalsById(supertest, log, id); const hits = signalsOpen.hits.hits.map((hit) => hit._source?.double).sort(); expect(hits).to.eql(['1.1', '1.2', '1.3']); From efbb04607a611a6a49f158eb86df9dc1e64d855e Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Wed, 9 Aug 2023 10:45:52 -0400 Subject: [PATCH 06/22] fix(slo): Handle error during SLO resources installation (#163440) --- .../plugins/observability/server/services/slo/slo_installer.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/observability/server/services/slo/slo_installer.ts b/x-pack/plugins/observability/server/services/slo/slo_installer.ts index b59612ca30253..d6e8b8295348f 100644 --- a/x-pack/plugins/observability/server/services/slo/slo_installer.ts +++ b/x-pack/plugins/observability/server/services/slo/slo_installer.ts @@ -37,7 +37,6 @@ export class DefaultSLOInstaller implements SLOInstaller { this.logger.error('Failed to install SLO common resources and summary transforms', { error, }); - throw error; } finally { this.isInstalling = false; clearTimeout(installTimeout); From 0c51ce6f05dd6a8a688516556970e49c071e282e Mon Sep 17 00:00:00 2001 From: Ying Mao Date: Wed, 9 Aug 2023 10:54:41 -0400 Subject: [PATCH 07/22] [Response Ops][Alerting] Adding `ignore_malformed` to `.alerts-*` index template settings (#163414) Resolves https://github.com/elastic/kibana/issues/161465 ## Summary Adds `ignore_malformed: true` to alerts index template settings. This ignores malformed content globally across all allowed mapping types. For existing alerts as data indices, the new setting is not applied directly to the existing concrete indices but will be applied whenever the alias rolls over and a new concrete index is created. ## Verify - Verify that after upgrading alerts indices created in an older version to this branch, alerts continue to be written and read as expected. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Vitalii Dmyterko --- .../server/alerts_service/alerts_service.test.ts | 2 ++ .../lib/create_or_update_index_template.test.ts | 1 + .../lib/create_or_update_index_template.ts | 1 + .../group4/alerts_as_data/install_resources.ts | 2 ++ .../rule_execution_logic/non_ecs_fields.ts | 11 +++++------ 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts b/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts index e3942b26ee6fa..5c4acce28b108 100644 --- a/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts +++ b/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts @@ -114,6 +114,7 @@ const getIndexTemplatePutBody = (opts?: GetIndexTemplatePutBodyOpts) => { name: '.alerts-ilm-policy', rollover_alias: `.alerts-${context ? context : 'test'}.alerts-${namespace}`, }, + 'index.mapping.ignore_malformed': true, 'index.mapping.total_fields.limit': 2500, }, mappings: { @@ -640,6 +641,7 @@ describe('Alerts Service', () => { name: '.alerts-ilm-policy', rollover_alias: `.alerts-empty.alerts-default`, }, + 'index.mapping.ignore_malformed': true, 'index.mapping.total_fields.limit': 2500, }, mappings: { diff --git a/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.test.ts b/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.test.ts index d4ce203a0d0e3..38c2207e5f410 100644 --- a/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.test.ts +++ b/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.test.ts @@ -42,6 +42,7 @@ const IndexTemplate = (namespace: string = 'default') => ({ name: 'test-ilm-policy', rollover_alias: `.alerts-test.alerts-${namespace}`, }, + 'index.mapping.ignore_malformed': true, 'index.mapping.total_fields.limit': 2500, }, }, diff --git a/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.ts b/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.ts index a17fad2d875ed..388fe6344a51f 100644 --- a/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.ts +++ b/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.ts @@ -54,6 +54,7 @@ export const getIndexTemplate = ({ rollover_alias: indexPatterns.alias, }, 'index.mapping.total_fields.limit': totalFieldsLimit, + 'index.mapping.ignore_malformed': true, }, mappings: { dynamic: false, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/install_resources.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/install_resources.ts index b6c86b49c7fba..e80a8f94d93b6 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/install_resources.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/install_resources.ts @@ -163,6 +163,7 @@ export default function createAlertsAsDataInstallResourcesTest({ getService }: F rollover_alias: '.alerts-test.patternfiring.alerts-default', }, mapping: { + ignore_malformed: 'true', total_fields: { limit: '2500', }, @@ -196,6 +197,7 @@ export default function createAlertsAsDataInstallResourcesTest({ getService }: F }); expect(contextIndex[indexName].settings?.index?.mapping).to.eql({ + ignore_malformed: 'true', total_fields: { limit: '2500', }, diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/non_ecs_fields.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/non_ecs_fields.ts index 32ae758b20807..f315dfabb4d86 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/non_ecs_fields.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/non_ecs_fields.ts @@ -56,7 +56,6 @@ export default ({ getService }: FtrProviderContext) => { }; }; - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/154277 describe('Non ECS fields in alert document source', () => { before(async () => { await esArchiver.load( @@ -259,6 +258,7 @@ export default ({ getService }: FtrProviderContext) => { // we don't validate it because geo_point is very complex type with many various representations: array, different object, string with few valid patterns // more on geo_point type https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-point.html + // since .alerts-* indices allow _ignore_malformed option, alert will be indexed for this document it('should fail creating alert when ECS field mapping is geo_point', async () => { const document = { client: { @@ -269,12 +269,11 @@ export default ({ getService }: FtrProviderContext) => { }, }; - const { errors } = await indexAndCreatePreviewAlert(document); + const { errors, alertSource } = await indexAndCreatePreviewAlert(document); - expect(errors[0]).toContain('Bulk Indexing of signals failed'); - expect(errors[0]).toContain( - 'failed to parse field [client.geo.location] of type [geo_point]' - ); + expect(errors).toEqual([]); + + expect(alertSource).toHaveProperty('client.geo.location', 'test test'); }); it('should strip invalid boolean values and left valid ones', async () => { From 143355a7f4a8379a35ed29d7417dba82379b2127 Mon Sep 17 00:00:00 2001 From: Marta Bondyra <4283304+mbondyra@users.noreply.github.com> Date: Wed, 9 Aug 2023 17:05:58 +0200 Subject: [PATCH 08/22] [Lens] Add tooltip for partition and heatmap filtering (#162716) ## Summary The breaking tests have nothing to do with this PR. I ran the [test PR and it broke too.](https://github.com/elastic/kibana/pull/163229/files) ### Functionality changes #### XY Chart Adds tooltip action for x series if it exists. The copy is different for time and categorical series. https://github.com/elastic/kibana/assets/4283304/2a043e04-c5b1-480d-be10-ae618145fb65 Screenshot 2023-08-04 at 17 37 39 Screenshot 2023-08-04 at 17 37 57 When filtering by one time interval we create a time picker filter and not regular filter now. #### Partition Chart Adds tooltip actions filters. Doesn't add them if we only have metric dimensions. https://github.com/elastic/kibana/assets/4283304/c4d427c3-fb81-4f9d-b4be-dcb5ba872fdb #### Heat map Chart Adds tooltip actions filters https://github.com/elastic/kibana/assets/4283304/68795a02-8d40-47af-8366-d7c4f88c6ce3 ### Code changes #### Changes to `MultiValueClickContext` 1. I changed the interface to: ``` export interface MultiValueClickContext { {...} data: { data: Array<{ cells: Array<{ column: number; row: number; }>; table: Pick; relation?: BooleanRelation; }>; {...} }; } ``` The important changes are accepting the array of data (this way we can pass multiple tables for different dataviews, for example for different layers for xy chart and we don't have run separate handlers for separate layers). Also we don't pass a single column and array of values (that then we have to convert to multiple rows inside of the functions) but a `cells` array. This way we can pass values that belong to different rows and columns. I also added a `relation` param so user can control if they prefer to use `AND` or `OR` relation for combined filter. If none is used, the filters are separate. Fixes https://github.com/elastic/kibana/issues/150304 --------- Co-authored-by: Stratoula Kalafateli --- .../common/types/expression_renderers.ts | 12 +- .../components/heatmap_component.test.tsx | 66 ++++ .../public/components/heatmap_component.tsx | 123 +++++-- .../expression_renderers/heatmap_renderer.tsx | 5 + .../utils/get_split_dimension_utils.test.ts | 2 +- .../public/utils/get_split_dimension_utils.ts | 1 + .../partition_vis_component.test.tsx.snap | 54 +++ .../partition_vis_component.test.tsx | 66 +++- .../components/partition_vis_component.tsx | 52 ++- .../expression_partition_vis/public/types.ts | 11 +- .../public/utils/filter_helpers.ts | 41 ++- .../__snapshots__/xy_chart.test.tsx.snap | 50 +++ .../components/tooltip/tooltip_actions.tsx | 259 ++++++++++++++ .../public/components/xy_chart.test.tsx | 330 +++++++++++------- .../public/components/xy_chart.tsx | 151 ++------ .../expression_xy/tsconfig.json | 2 + ...ate_filters_from_multi_value_click.test.ts | 188 ++++++++-- .../create_filters_from_multi_value_click.ts | 107 +++--- .../actions/multi_value_click_action.ts | 37 +- src/plugins/data/public/plugin.ts | 2 +- .../public/lib/triggers/triggers.ts | 33 +- .../workspace_panel/workspace_panel.test.tsx | 4 +- .../workspace_panel/workspace_panel.tsx | 4 +- .../lens/public/embeddable/embeddable.tsx | 63 ++-- x-pack/plugins/lens/public/types.ts | 6 + x-pack/plugins/lens/public/utils.test.ts | 77 ++-- x-pack/plugins/lens/public/utils.ts | 42 ++- .../visualization_actions/lens_embeddable.tsx | 8 +- .../functional/apps/lens/group4/dashboard.ts | 7 +- 29 files changed, 1330 insertions(+), 473 deletions(-) create mode 100644 src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip_actions.tsx diff --git a/src/plugins/chart_expressions/expression_heatmap/common/types/expression_renderers.ts b/src/plugins/chart_expressions/expression_heatmap/common/types/expression_renderers.ts index b59a8ee2c5166..dfeff855f867f 100644 --- a/src/plugins/chart_expressions/expression_heatmap/common/types/expression_renderers.ts +++ b/src/plugins/chart_expressions/expression_heatmap/common/types/expression_renderers.ts @@ -10,7 +10,11 @@ import type { PaletteRegistry } from '@kbn/coloring'; import type { ChartsPluginSetup, ChartsPluginStart } from '@kbn/charts-plugin/public'; import type { DatatableUtilitiesService } from '@kbn/data-plugin/common'; import type { IFieldFormat, SerializedFieldFormat } from '@kbn/field-formats-plugin/common'; -import type { RangeSelectContext, ValueClickContext } from '@kbn/embeddable-plugin/public'; +import type { + RangeSelectContext, + ValueClickContext, + MultiValueClickContext, +} from '@kbn/embeddable-plugin/public'; import type { PersistedState } from '@kbn/visualizations-plugin/public'; import { IInterpreterRenderHandlers } from '@kbn/expressions-plugin/common'; import type { HeatmapExpressionProps } from './expression_functions'; @@ -25,6 +29,11 @@ export interface BrushEvent { data: RangeSelectContext['data']; } +export interface MultiFilterEvent { + name: 'multiFilter'; + data: MultiValueClickContext['data']; +} + export type FormatFactory = (mapping?: SerializedFieldFormat) => IFieldFormat; export type HeatmapRenderProps = HeatmapExpressionProps & { @@ -35,6 +44,7 @@ export type HeatmapRenderProps = HeatmapExpressionProps & { datatableUtilities: DatatableUtilitiesService; onClickValue: (data: FilterEvent['data']) => void; onSelectRange: (data: BrushEvent['data']) => void; + onClickMultiValue: (data: MultiFilterEvent['data']) => void; paletteService: PaletteRegistry; uiState: PersistedState; interactive: boolean; diff --git a/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.test.tsx b/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.test.tsx index 34b4df99c9af4..eef7fd3eb6aba 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.test.tsx +++ b/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.test.tsx @@ -14,6 +14,8 @@ import { GeometryValue, XYChartSeriesIdentifier, Tooltip, + TooltipAction, + TooltipValue, } from '@elastic/charts'; import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; import { EmptyPlaceholder } from '@kbn/charts-plugin/public'; @@ -121,6 +123,7 @@ describe('HeatmapComponent', function () { uiState, onClickValue: jest.fn(), onSelectRange: jest.fn(), + onClickMultiValue: jest.fn(), datatableUtilities: createDatatableUtilitiesMock(), paletteService: palettesRegistry, formatFactory: formatService.deserialize, @@ -444,4 +447,67 @@ describe('HeatmapComponent', function () { expect(settingsComponent.prop('ariaUseDefaultSummary')).toEqual(true); }); }); + + describe('tooltip', () => { + it('should not have actions if chart is not interactive', () => { + const component = shallowWithIntl(); + const tooltip = component.find(Tooltip); + const actions = tooltip.prop('actions'); + expect(actions).toBeUndefined(); + }); + it('should have tooltip actions when the chart is fully configured and interactive', () => { + const component = shallowWithIntl(); + const tooltip = component.find(Tooltip); + const actions = tooltip.prop('actions'); + expect(actions?.length).toBe(1); + expect(actions).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + onSelect: expect.any(Function), + disabled: expect.any(Function), + }), + ]) + ); + }); + + it('selecting correct actions calls a callback with correct filter data', () => { + const component = shallowWithIntl(); + const tooltip = component.find(Tooltip); + const actions = tooltip.prop('actions') as TooltipAction[]; + actions[0].onSelect!( + [ + { + label: 'Dest', + datum: { + x: 'a', + y: 'd', + value: 0, + originalIndex: 0, + }, + } as TooltipValue, + { + label: 'Test', + datum: { + x: 'a', + y: 'd', + value: 0, + originalIndex: 0, + }, + } as TooltipValue, + ], + [] + ); + expect(wrapperProps.onClickMultiValue).toHaveBeenCalledWith({ + data: [ + { + cells: [ + { column: 1, row: 0 }, + { column: 2, row: 0 }, + ], + table: wrapperProps.data, + }, + ], + }); + }); + }); }); diff --git a/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx b/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx index 95856d1bae485..97e5979766089 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx +++ b/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx @@ -18,12 +18,13 @@ import { ScaleType, Settings, TooltipType, - TooltipProps, ESFixedIntervalUnit, ESCalendarIntervalUnit, PartialTheme, SettingsProps, Tooltip, + SeriesIdentifier, + TooltipValue, } from '@elastic/charts'; import type { CustomPaletteState } from '@kbn/charts-plugin/public'; import { search } from '@kbn/data-plugin/public'; @@ -36,6 +37,7 @@ import { DEFAULT_LEGEND_SIZE, LegendSizeToPixels, } from '@kbn/visualizations-plugin/common/constants'; +import { i18n } from '@kbn/i18n'; import { DatatableColumn } from '@kbn/expressions-plugin/public'; import { IconChartHeatmap } from '@kbn/chart-icons'; import { getOverridesFor } from '@kbn/chart-expressions-common'; @@ -138,7 +140,7 @@ function computeColorRanges( export const HeatmapComponent: FC = memo( ({ - data, + data: table, args, timeZone, formatFactory, @@ -147,6 +149,7 @@ export const HeatmapComponent: FC = memo( datatableUtilities, onClickValue, onSelectRange, + onClickMultiValue, paletteService, uiState, interactive, @@ -204,8 +207,6 @@ export const HeatmapComponent: FC = memo( }, [renderComplete] ); - - const table = data; const valueAccessor = args.valueAccessor ? getAccessorByDimension(args.valueAccessor, table.columns) : undefined; @@ -221,10 +222,10 @@ export const HeatmapComponent: FC = memo( ? getAccessorByDimension(args.yAccessor, table.columns) : undefined; const splitChartRowAccessor = args.splitRowAccessor - ? getSplitDimensionAccessor(data.columns, args.splitRowAccessor, formatFactory) + ? getSplitDimensionAccessor(table.columns, args.splitRowAccessor, formatFactory) : undefined; const splitChartColumnAccessor = args.splitColumnAccessor - ? getSplitDimensionAccessor(data.columns, args.splitColumnAccessor, formatFactory) + ? getSplitDimensionAccessor(table.columns, args.splitColumnAccessor, formatFactory) : undefined; const xAxisColumnIndex = table.columns.findIndex((v) => v.id === xAccessor); @@ -260,6 +261,8 @@ export const HeatmapComponent: FC = memo( datatables: [formattedTable.table], }); + const hasTooltipActions = interactive; + const onElementClick = useCallback( (e: HeatmapElementEvent[]) => { const cell = e[0][0]; @@ -277,6 +280,7 @@ export const HeatmapComponent: FC = memo( }), column: xAxisColumnIndex, value: x, + table, }, ...(yAxisColumn ? [ @@ -290,6 +294,7 @@ export const HeatmapComponent: FC = memo( }), column: yAxisColumnIndex, value: y, + table, }, ] : []), @@ -317,15 +322,10 @@ export const HeatmapComponent: FC = memo( points.push(point); } } - const context: FilterEvent['data'] = { - data: points.map((point) => ({ - row: point.row, - column: point.column, - value: point.value, - table, - })), - }; - onClickValue(context); + + onClickValue({ + data: points, + }); }, [ args.splitColumnAccessor, @@ -472,10 +472,6 @@ export const HeatmapComponent: FC = memo( } } - const tooltip: TooltipProps = { - type: args.showTooltip ? TooltipType.Follow : TooltipType.None, - }; - const valueFormatter = (d: number) => { let value = d; @@ -598,6 +594,69 @@ export const HeatmapComponent: FC = memo( const xAxisTitle = args.gridConfig.xTitle ?? xAxisColumn?.name; const yAxisTitle = args.gridConfig.yTitle ?? yAxisColumn?.name; + const filterSelectedTooltipValues = ( + tooltipSelectedValues: Array< + TooltipValue, SeriesIdentifier> + > + ) => { + const { datum } = tooltipSelectedValues[0]; + if (!datum) { + return; + } + const { x, y } = datum; + + const shouldFilterByX = tooltipSelectedValues.some( + ({ label }) => label === xAxisColumn?.name + ); + + const shouldFilterByY = tooltipSelectedValues.some( + ({ label }) => label === yAxisColumn?.name + ); + + const cells = [ + ...(xAxisColumn && shouldFilterByX + ? [ + { + column: xAxisColumnIndex, + row: table.rows.findIndex((r) => { + if (!xAxisColumn) return false; + if (formattedTable.formattedColumns[xAxisColumn.id]) { + // stringify the value to compare with the chart value + return xValuesFormatter.convert(r[xAxisColumn.id]) === x; + } + return r[xAxisColumn.id] === x; + }), + }, + ] + : []), + ...(yAxisColumn && shouldFilterByY + ? [ + { + column: yAxisColumnIndex, + row: table.rows.findIndex((r) => { + if (formattedTable.formattedColumns[yAxisColumn.id]) { + // stringify the value to compare with the chart value + return yValuesFormatter.convert(r[yAxisColumn.id]) === y; + } + return r[yAxisColumn.id] === y; + }), + }, + ] + : []), + ]; + + if (cells.length) { + onClickMultiValue({ + data: [ + { + table, + cells, + }, + ], + }); + } + }; + return ( <> {showLegend !== undefined && ( @@ -619,7 +678,31 @@ export const HeatmapComponent: FC = memo( splitColumnAccessor={splitChartColumnAccessor} splitRowAccessor={splitChartRowAccessor} /> - + , SeriesIdentifier> + actions={ + hasTooltipActions + ? [ + { + disabled: (selected) => selected.length < 1, + label: (selected) => + selected.length === 0 + ? i18n.translate( + 'expressionHeatmap.tooltipActions.emptyFilterSelection', + { + defaultMessage: 'Select at least one series to filter', + } + ) + : i18n.translate('expressionHeatmap.tooltipActions.filterValues', { + defaultMessage: 'Filter {seriesNumber} series', + values: { seriesNumber: selected.length }, + }), + onSelect: filterSelectedTooltipValues, + }, + ] + : undefined + } + type={args.showTooltip ? TooltipType.Follow : TooltipType.None} + /> { handlers.event({ name: 'brush', data }); }; + const onClickMultiValue = (data: MultiFilterEvent['data']) => { + handlers.event({ name: 'multiFilter', data }); + }; const renderComplete = () => { const executionContext = handlers.getExecutionContext(); @@ -97,6 +101,7 @@ export const heatmapRenderer: ( chartsActiveCursorService={plugins.charts.activeCursor} syncTooltips={config.syncTooltips} syncCursor={config.syncCursor} + onClickMultiValue={onClickMultiValue} /> diff --git a/src/plugins/chart_expressions/expression_heatmap/public/utils/get_split_dimension_utils.test.ts b/src/plugins/chart_expressions/expression_heatmap/public/utils/get_split_dimension_utils.test.ts index 6b510b28c8060..6a4912f0af501 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/utils/get_split_dimension_utils.test.ts +++ b/src/plugins/chart_expressions/expression_heatmap/public/utils/get_split_dimension_utils.test.ts @@ -136,7 +136,7 @@ describe('createSplitPoint', () => { const point = createSplitPoint(splitDimension, 'c', defaultFormatter, data); expect(defaultFormatter).toHaveBeenCalledTimes(1); - expect(point).toStrictEqual({ column: 2, row: 1, value: 'c' }); + expect(point).toStrictEqual({ column: 2, row: 1, value: 'c', table: data }); }); it('returns undefined if value is not found in the table', () => { diff --git a/src/plugins/chart_expressions/expression_heatmap/public/utils/get_split_dimension_utils.ts b/src/plugins/chart_expressions/expression_heatmap/public/utils/get_split_dimension_utils.ts index e59d6c1aec28b..ec4c69ad233c3 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/utils/get_split_dimension_utils.ts +++ b/src/plugins/chart_expressions/expression_heatmap/public/utils/get_split_dimension_utils.ts @@ -51,6 +51,7 @@ export function createSplitPoint( row: splitPointRowIndex, column: table.columns.findIndex((column) => column.id === accessor), value: table.rows[splitPointRowIndex][accessor], + table, }; } } diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/components/__snapshots__/partition_vis_component.test.tsx.snap b/src/plugins/chart_expressions/expression_partition_vis/public/components/__snapshots__/partition_vis_component.test.tsx.snap index 65fa256304fde..0b8a82459fd97 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/components/__snapshots__/partition_vis_component.test.tsx.snap +++ b/src/plugins/chart_expressions/expression_partition_vis/public/components/__snapshots__/partition_vis_component.test.tsx.snap @@ -223,6 +223,15 @@ exports[`PartitionVisComponent should render correct structure for donut 1`] = ` > { + it('should not have actions if chart is not interactive', () => { + const component = shallow(); + const tooltip = component.find(Tooltip); + const actions = tooltip.prop('actions'); + expect(actions).toBeUndefined(); + }); + it('should not have actions if chart has only metrics', () => { + const noBucketParams = { + ...wrapperProps, + visParams: { + ...wrapperProps.visParams, + dimensions: { ...wrapperProps.visParams.dimensions, buckets: [] }, + }, + }; + + const component = shallow(); + const tooltip = component.find(Tooltip); + const actions = tooltip.prop('actions'); + expect(actions).toBeUndefined(); + }); + it('should have tooltip actions when the chart is fully configured and interactive', () => { + const component = shallow(); + const tooltip = component.find(Tooltip); + const actions = tooltip.prop('actions'); + expect(actions?.length).toBe(1); + expect(actions).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + onSelect: expect.any(Function), + disabled: expect.any(Function), + }), + ]) + ); + }); + it('selecting correct actions calls a callback with correct filter data', () => { + const component = shallow(); + const tooltip = component.find(Tooltip); + const actions = tooltip.prop('actions') as TooltipAction[]; + actions[0].onSelect!( + [ + { + label: 'JetBeats', + color: '#79aad9', + isHighlighted: false, + isVisible: true, + seriesIdentifier: { + specId: 'donut', + key: 'JetBeats', + }, + value: 655, + formattedValue: '655', + valueAccessor: 1, + }, + ], + [] + ); + expect(wrapperProps.fireEvent).toHaveBeenCalledWith({ + name: 'multiFilter', + data: { data: [{ cells: [{ column: 0, row: 2 }], table: wrapperProps.visData }] }, + }); + }); + }); }); diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx index c151741158ac1..de1c977cbdadf 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx +++ b/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx @@ -20,7 +20,9 @@ import { PartitionElementEvent, SettingsProps, Tooltip, + TooltipValue, } from '@elastic/charts'; +import { i18n } from '@kbn/i18n'; import { useEuiTheme } from '@elastic/eui'; import type { PaletteRegistry } from '@kbn/coloring'; import { LegendToggle, ChartsPluginSetup } from '@kbn/charts-plugin/public'; @@ -72,6 +74,7 @@ import { } from './partition_vis_component.styles'; import { filterOutConfig } from '../utils/filter_out_config'; import { ColumnCellValueActions, FilterEvent, StartDeps } from '../types'; +import { getMultiFilterCells } from '../utils/filter_helpers'; declare global { interface Window { @@ -205,6 +208,7 @@ const PartitionVisComponent = (props: PartitionVisComponentProps) => { splitChartDimension, splitChartFormatter ); + props.fireEvent({ name: 'filter', data: { data } }); }, [metricColumn.id, originalVisData, props, visParams.dimensions.metrics.length] @@ -385,10 +389,7 @@ const PartitionVisComponent = (props: PartitionVisComponentProps) => { ); const fixedViewPort = document.getElementById('app-fixed-viewport'); - const tooltip: TooltipProps = { - ...(fixedViewPort ? { boundary: fixedViewPort } : {}), - type: visParams.addTooltip ? TooltipType.Follow : TooltipType.None, - }; + const legendPosition = visParams.legendPosition ?? Position.Right; const splitChartColumnAccessor = splitColumn @@ -405,6 +406,49 @@ const PartitionVisComponent = (props: PartitionVisComponentProps) => { ? getColumnByAccessor(splitRow[0], visData.columns) : undefined; + const hasTooltipActions = + interactive && bucketAccessors.filter((a) => a !== 'metric-name').length > 0; + + const tooltip: TooltipProps = { + ...(fixedViewPort ? { boundary: fixedViewPort } : {}), + type: visParams.addTooltip ? TooltipType.Follow : TooltipType.None, + actions: hasTooltipActions + ? [ + { + disabled: (selected) => selected.length < 1, + label: (selected) => + selected.length === 0 + ? i18n.translate('expressionPartitionVis.tooltipActions.emptyFilterSelection', { + defaultMessage: 'Select at least one series to filter', + }) + : i18n.translate('expressionPartitionVis.tooltipActions.filterValues', { + defaultMessage: 'Filter {seriesNumber} series', + values: { seriesNumber: selected.length }, + }), + onSelect: ( + tooltipSelectedValues: Array< + TooltipValue, SeriesIdentifier> + > + ) => { + const cells = getMultiFilterCells(tooltipSelectedValues, bucketColumns, visData); + + props.fireEvent({ + name: 'multiFilter', + data: { + data: [ + { + table: visData, + cells, + }, + ], + }, + }); + }, + }, + ] + : undefined, + }; + /** * Checks whether data have all zero values. * If so, the no data container is loaded. diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/types.ts b/src/plugins/chart_expressions/expression_partition_vis/public/types.ts index 77636d3a41832..0beca2e79de8d 100755 --- a/src/plugins/chart_expressions/expression_partition_vis/public/types.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/public/types.ts @@ -5,7 +5,11 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { CellValueContext, ValueClickContext } from '@kbn/embeddable-plugin/public'; +import type { + CellValueContext, + ValueClickContext, + MultiValueClickContext, +} from '@kbn/embeddable-plugin/public'; import { ChartsPluginSetup, ChartsPluginStart } from '@kbn/charts-plugin/public'; import { Plugin as ExpressionsPublicPlugin, @@ -36,6 +40,11 @@ export interface FilterEvent { data: ValueClickContext['data']; } +export interface MultiFilterEvent { + name: 'multiFilter'; + data: MultiValueClickContext['data']; +} + export interface CellValueAction { id: string; iconType: string; diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/filter_helpers.ts b/src/plugins/chart_expressions/expression_partition_vis/public/utils/filter_helpers.ts index c7b793d87149f..b34a4f74147d8 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/utils/filter_helpers.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/filter_helpers.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { LayerValue, SeriesIdentifier } from '@elastic/charts'; +import { LayerValue, SeriesIdentifier, TooltipValue } from '@elastic/charts'; import { Datatable, DatatableColumn } from '@kbn/expressions-plugin/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { ValueClickContext } from '@kbn/embeddable-plugin/public'; @@ -26,6 +26,45 @@ export const canFilter = async ( return Boolean(filters.length); }; +export const getMultiFilterCells = ( + tooltipSelectedValues: Array, SeriesIdentifier>>, + bucketColumns: Array>, + visData: Datatable +) => { + const row = visData.rows.findIndex((r) => + tooltipSelectedValues.every(({ valueAccessor, seriesIdentifier }) => { + if (typeof valueAccessor !== 'number' || valueAccessor < 1) return; + const index = valueAccessor - 1; + const bucketColumnId = bucketColumns[index].id; + if (!bucketColumnId) return; + return r[bucketColumnId] === seriesIdentifier.key; + }) + ); + + return tooltipSelectedValues + .map(({ valueAccessor }) => { + if (typeof valueAccessor !== 'number' || valueAccessor < 1) return; + const index = valueAccessor - 1; + const bucketColumnId = bucketColumns[index].id; + if (!bucketColumnId) return; + const column = visData.columns.findIndex((c) => c.id === bucketColumnId); + + if (column === -1) { + return; + } + + return { + column, + row, + }; + }) + .filter(nonNullable); +}; + +function nonNullable(v: T): v is NonNullable { + return v != null; +} + export const getFilterClickData = ( clickedLayers: LayerValue[], bucketColumns: Array>, diff --git a/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap b/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap index fb8faf123fa66..fe76259b65889 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap +++ b/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap @@ -565,6 +565,11 @@ exports[`XYChart component it renders area 1`] = ` "label": [Function], "onSelect": [Function], }, + Object { + "disabled": [Function], + "label": [Function], + "onSelect": [Function], + }, ] } headerFormatter={[Function]} @@ -1568,6 +1573,11 @@ exports[`XYChart component it renders bar 1`] = ` "label": [Function], "onSelect": [Function], }, + Object { + "disabled": [Function], + "label": [Function], + "onSelect": [Function], + }, ] } headerFormatter={[Function]} @@ -2571,6 +2581,11 @@ exports[`XYChart component it renders horizontal bar 1`] = ` "label": [Function], "onSelect": [Function], }, + Object { + "disabled": [Function], + "label": [Function], + "onSelect": [Function], + }, ] } headerFormatter={[Function]} @@ -3574,6 +3589,11 @@ exports[`XYChart component it renders line 1`] = ` "label": [Function], "onSelect": [Function], }, + Object { + "disabled": [Function], + "label": [Function], + "onSelect": [Function], + }, ] } headerFormatter={[Function]} @@ -4577,6 +4597,11 @@ exports[`XYChart component it renders stacked area 1`] = ` "label": [Function], "onSelect": [Function], }, + Object { + "disabled": [Function], + "label": [Function], + "onSelect": [Function], + }, ] } headerFormatter={[Function]} @@ -5580,6 +5605,11 @@ exports[`XYChart component it renders stacked bar 1`] = ` "label": [Function], "onSelect": [Function], }, + Object { + "disabled": [Function], + "label": [Function], + "onSelect": [Function], + }, ] } headerFormatter={[Function]} @@ -6583,6 +6613,11 @@ exports[`XYChart component it renders stacked horizontal bar 1`] = ` "label": [Function], "onSelect": [Function], }, + Object { + "disabled": [Function], + "label": [Function], + "onSelect": [Function], + }, ] } headerFormatter={[Function]} @@ -7616,6 +7651,11 @@ exports[`XYChart component split chart should render split chart if both, splitR "label": [Function], "onSelect": [Function], }, + Object { + "disabled": [Function], + "label": [Function], + "onSelect": [Function], + }, ] } headerFormatter={[Function]} @@ -8857,6 +8897,11 @@ exports[`XYChart component split chart should render split chart if splitColumnA "label": [Function], "onSelect": [Function], }, + Object { + "disabled": [Function], + "label": [Function], + "onSelect": [Function], + }, ] } headerFormatter={[Function]} @@ -10091,6 +10136,11 @@ exports[`XYChart component split chart should render split chart if splitRowAcce "label": [Function], "onSelect": [Function], }, + Object { + "disabled": [Function], + "label": [Function], + "onSelect": [Function], + }, ] } headerFormatter={[Function]} diff --git a/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip_actions.tsx b/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip_actions.tsx new file mode 100644 index 0000000000000..04cec59fd0b1d --- /dev/null +++ b/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip_actions.tsx @@ -0,0 +1,259 @@ +/* + * 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 { Datum, TooltipAction, TooltipValue, XYChartSeriesIdentifier } from '@elastic/charts'; +import { + getAccessorByDimension, + getColumnByAccessor, +} from '@kbn/visualizations-plugin/common/utils'; +import { FormatFactory } from '@kbn/visualization-ui-components'; +import { FieldFormat } from '@kbn/field-formats-plugin/common'; +import { i18n } from '@kbn/i18n'; +import { MultiClickTriggerEvent } from '@kbn/charts-plugin/public'; +import { Datatable } from '@kbn/expressions-plugin/common'; +import { BooleanRelation } from '@kbn/es-query'; +import { isTimeChart } from '../../../common/helpers'; +import { CommonXYDataLayerConfig } from '../../../common'; +import { DatatablesWithFormatInfo, LayersFieldFormats } from '../../helpers'; +import { MultiFilterEvent } from '../../types'; + +type XYTooltipValue = TooltipValue, XYChartSeriesIdentifier>; + +function nonNullable(v: T): v is NonNullable { + return v != null; +} + +export function createSplitPoint( + accessor: string | number, + value: string | number | undefined, + rows: Datatable['rows'], + table: Datatable +) { + if (value === undefined) return; + const splitPointRowIndex = rows.findIndex((row) => { + if (Array.isArray(value)) { + return value.includes(row[accessor]); + } + return row[accessor] === value; + }); + if (splitPointRowIndex !== -1) { + return { + row: splitPointRowIndex, + column: table.columns.findIndex((column) => column.id === accessor), + value: table.rows[splitPointRowIndex][accessor], + table, + }; + } +} + +export const getXSeriesPoint = ( + layer: CommonXYDataLayerConfig, + value: any, + fieldFormats: LayersFieldFormats, + formattedDatatables: DatatablesWithFormatInfo, + xAxisFormatter: FieldFormat, + formatFactory: FormatFactory +) => { + const { table } = layer; + const xColumn = layer.xAccessor && getColumnByAccessor(layer.xAccessor, table.columns); + const xAccessor = layer.xAccessor + ? getAccessorByDimension(layer.xAccessor, table.columns) + : undefined; + + const xFormat = xColumn ? fieldFormats[layer.layerId].xAccessors[xColumn.id] : undefined; + const currentXFormatter = + xAccessor && formattedDatatables[layer.layerId]?.formattedColumns[xAccessor] && xColumn + ? formatFactory(xFormat) + : xAxisFormatter; + + const rowIndex = table.rows.findIndex((row) => { + if (xAccessor) { + if (formattedDatatables[layer.layerId]?.formattedColumns[xAccessor]) { + // stringify the value to compare with the chart value + return currentXFormatter.convert(row[xAccessor]) === value; + } + return row[xAccessor] === value; + } + }); + + return { + row: rowIndex, + column: table.columns.findIndex((col) => col.id === xAccessor), + table, + value: xAccessor ? table.rows[rowIndex][xAccessor] : value, + }; +}; + +function getXSeriesValue(dataLayers: CommonXYDataLayerConfig[], firstSeries: XYTooltipValue) { + const layer = dataLayers.find((l) => + firstSeries.seriesIdentifier.seriesKeys.some((key: string | number) => + l.accessors.some( + (accessor) => getAccessorByDimension(accessor, l.table.columns) === key.toString() + ) + ) + ); + if (!layer) return; + + const { table } = layer; + + const xAccessor = layer.xAccessor + ? getAccessorByDimension(layer.xAccessor, table.columns) + : undefined; + + return xAccessor ? firstSeries.datum?.[xAccessor] : null; +} + +export const getTooltipActions = ( + dataLayers: CommonXYDataLayerConfig[], + onClickMultiValue: (data: MultiFilterEvent['data']) => void, + fieldFormats: LayersFieldFormats, + formattedDatatables: DatatablesWithFormatInfo, + xAxisFormatter: FieldFormat, + formatFactory: FormatFactory, + isEnabled?: boolean +) => { + if (!isEnabled) return; + const hasSplitAccessors = dataLayers.some((l) => l.splitAccessors?.length); + const hasXAxis = dataLayers.every((l) => l.xAccessor); + const isTimeViz = isTimeChart(dataLayers); + + if (!hasSplitAccessors && !hasXAxis) return; + + const xSeriesActions: Array> = hasXAxis + ? [ + { + disabled: () => !hasXAxis, + label: (_, [firstSeries]: XYTooltipValue[]) => { + if (isTimeViz) { + return i18n.translate('expressionXY.tooltipActions.filterByTime', { + defaultMessage: 'Filter by time', + }); + } + + const value = getXSeriesValue(dataLayers, firstSeries); + + return i18n.translate('expressionXY.tooltipActions.filterForXSeries', { + defaultMessage: 'Filter for {value}', + values: { + value: xAxisFormatter.convert(value) || value, + }, + }); + }, + + onSelect: (_: XYTooltipValue[], [firstSeries]: XYTooltipValue[]) => { + const layer = dataLayers.find((l) => + firstSeries.seriesIdentifier.seriesKeys.some((key: string | number) => + l.accessors.some( + (accessor) => getAccessorByDimension(accessor, l.table.columns) === key.toString() + ) + ) + ); + if (!layer) return; + + const value = getXSeriesValue(dataLayers, firstSeries); + + const xSeriesPoint = getXSeriesPoint( + layer, + value, + fieldFormats, + formattedDatatables, + xAxisFormatter, + formatFactory + ); + + const context: MultiFilterEvent['data'] = { + data: [ + { + table: xSeriesPoint.table, + cells: [ + { + row: xSeriesPoint.row, + column: xSeriesPoint.column, + }, + ], + }, + ], + }; + onClickMultiValue(context); + }, + }, + ] + : []; + + const breakdownTooltipActions: Array> = + hasSplitAccessors + ? [ + { + disabled: (selected) => selected.length < 1, + label: (selected) => + selected.length === 0 + ? i18n.translate('expressionXY.tooltipActions.emptyFilterSelection', { + defaultMessage: 'Select at least one series to filter', + }) + : i18n.translate('expressionXY.tooltipActions.filterValues', { + defaultMessage: 'Filter {seriesNumber} selected series', + values: { seriesNumber: selected.length }, + }), + onSelect: (tooltipSelectedValues: XYTooltipValue[]) => { + const layerIndexes: number[] = []; + tooltipSelectedValues.forEach((v) => { + const index = dataLayers.findIndex((l) => + v.seriesIdentifier.seriesKeys.some((key: string | number) => + l.accessors.some( + (accessor) => + getAccessorByDimension(accessor, l.table.columns) === key.toString() + ) + ) + ); + if (!layerIndexes.includes(index) && index !== -1) { + layerIndexes.push(index); + } + }); + + const filterPoints: MultiClickTriggerEvent['data']['data'] = []; + + if (!layerIndexes.length) return; + layerIndexes.forEach((layerIndex) => { + const layer = dataLayers[layerIndex]; + const { table } = layer; + + if (layer.splitAccessors?.length !== 1) return; + + const splitAccessor = getAccessorByDimension( + layer.splitAccessors[0], + table.columns + ); + const splitPoints = tooltipSelectedValues + .map((v) => + createSplitPoint( + splitAccessor, + v.datum?.[splitAccessor], + formattedDatatables[layer.layerId].table.rows, + table + ) + ) + .filter(nonNullable); + if (splitPoints.length) { + filterPoints.push({ + cells: splitPoints.map(({ row, column }) => ({ row, column })), + relation: BooleanRelation.OR, + table, + }); + } + }); + if (filterPoints?.length) { + onClickMultiValue({ + data: filterPoints, + }); + } + }, + }, + ] + : []; + return [...xSeriesActions, ...breakdownTooltipActions]; +}; diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx index a43e4f1c05410..4a9e63c5ad7b3 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx @@ -107,6 +107,7 @@ describe('XYChart component', () => { convertSpy = jest.fn((x) => x); getFormatSpy = jest.fn(); getFormatSpy.mockReturnValue({ convert: convertSpy }); + jest.clearAllMocks(); defaultProps = { data: dataPluginMock.createStartContract(), @@ -1140,126 +1141,6 @@ describe('XYChart component', () => { expect(headerFormatter).toBeUndefined(); }); - test('should not have tooltip actions for the detailed tooltip', () => { - const { args, data } = sampleArgs(); - - const wrapper = mountWithIntl( - - ); - - const tooltip = wrapper.find(Tooltip); - const actions = tooltip.prop('actions'); - expect(actions).toBeUndefined(); - }); - - test('should not have tooltip actions for no split accessor', () => { - const { args, data } = sampleArgs(); - - const wrapper = mountWithIntl( - - ); - - const tooltip = wrapper.find(Tooltip); - const actions = tooltip.prop('actions'); - expect(actions).toBeUndefined(); - }); - - test('should have tooltip actions for split accessor and default tooltip', () => { - const { args, data } = sampleArgs(); - - const wrapper = mountWithIntl( - - ); - - const tooltip = wrapper.find(Tooltip); - const actions = tooltip.prop('actions'); - expect(actions?.length).toBe(1); - expect(actions).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - onSelect: expect.any(Function), - disabled: expect.any(Function), - }), - ]) - ); - }); - test('onElementClick returns correct context data', () => { const geometry: GeometryValue = { x: 5, y: 1, accessor: 'y1', mark: null, datum: {} }; const series = { @@ -3548,4 +3429,213 @@ describe('XYChart component', () => { } }); }); + + describe('tooltip actions', () => { + test('should not have tooltip actions for the detailed tooltip', () => { + const { args, data } = sampleArgs(); + + const wrapper = mountWithIntl( + + ); + + const tooltip = wrapper.find(Tooltip); + const actions = tooltip.prop('actions'); + expect(actions).toBeUndefined(); + }); + test('should not have tooltip action when there is no split accessor nor x serie', () => { + const { args, data } = sampleArgs(); + + const wrapper = mountWithIntl( + + ); + + const tooltip = wrapper.find(Tooltip); + const actions = tooltip.prop('actions'); + expect(actions).toBeUndefined(); + }); + test('should not have only x series tooltip action when there is no split accessor', () => { + const { args, data } = sampleArgs(); + + const wrapper = mountWithIntl( + + ); + + const tooltip = wrapper.find(Tooltip); + const actions = tooltip.prop('actions'); + expect(actions?.length).toBe(1); + expect(actions).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + onSelect: expect.any(Function), + disabled: expect.any(Function), + }), + ]) + ); + }); + test('should have tooltip actions for split accessor and x series', () => { + const { args, data } = sampleArgs(); + + const wrapper = mountWithIntl( + + ); + + const tooltip = wrapper.find(Tooltip); + const actions = tooltip.prop('actions'); + expect(actions?.length).toBe(2); + expect(actions).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + onSelect: expect.any(Function), + disabled: expect.any(Function), + }), + ]) + ); + }); + test('should have tooltip actions for split accessor', () => { + const { args, data } = sampleArgs(); + + const wrapper = mountWithIntl( + + ); + + const tooltip = wrapper.find(Tooltip); + const actions = tooltip.prop('actions'); + expect(actions?.length).toBe(1); + expect(actions).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + onSelect: expect.any(Function), + disabled: expect.any(Function), + }), + ]) + ); + }); + test('should call onClickMultiValue with a correct data for multiple series selected', () => {}); + test('should call onClickMultiValue with a correct data for time selected', () => {}); + }); }); diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx index e1ad4fa19d1c0..b8ac9d5cd0bbb 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx @@ -8,7 +8,6 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { css } from '@emotion/react'; -import { i18n } from '@kbn/i18n'; import { Chart, Settings, @@ -30,13 +29,12 @@ import { XYChartElementEvent, Tooltip, XYChartSeriesIdentifier, - TooltipValue, SettingsProps, } from '@elastic/charts'; import { partition } from 'lodash'; import { IconType } from '@elastic/eui'; import { PaletteRegistry } from '@kbn/coloring'; -import { Datatable, RenderMode } from '@kbn/expressions-plugin/common'; +import { RenderMode } from '@kbn/expressions-plugin/common'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { EmptyPlaceholder, LegendToggle } from '@kbn/charts-plugin/public'; import { EventAnnotationServiceType } from '@kbn/event-annotation-plugin/public'; @@ -113,6 +111,7 @@ import { XYCurrentTime } from './xy_current_time'; import './xy_chart.scss'; import { TooltipHeader } from './tooltip'; import { LegendColorPickerWrapperContext, LegendColorPickerWrapper } from './legend_color_picker'; +import { createSplitPoint, getTooltipActions, getXSeriesPoint } from './tooltip/tooltip_actions'; declare global { interface Window { @@ -150,7 +149,6 @@ export type XYChartRenderProps = Omit & { function nonNullable(v: T): v is NonNullable { return v != null; } - function getValueLabelsStyling(isHorizontal: boolean): { displayValue: RecursivePartial; } { @@ -184,28 +182,6 @@ function getIconForSeriesType(layer: CommonXYDataLayerConfig): IconType { ); } -function createSplitPoint( - accessor: string | number, - value: string | number, - rows: Datatable['rows'], - table: Datatable -) { - const splitPointRowIndex = rows.findIndex((row) => { - if (Array.isArray(value)) { - return value.includes(row[accessor]); - } - return row[accessor] === value; - }); - if (splitPointRowIndex !== -1) { - return { - row: splitPointRowIndex, - column: table.columns.findIndex((column) => column.id === accessor), - value: table.rows[splitPointRowIndex][accessor], - table, - }; - } -} - export const XYChartReportable = React.memo(XYChart); export function XYChart({ @@ -560,59 +536,11 @@ export function XYChart({ valueLabels !== ValueLabelModes.HIDE && getValueLabelsStyling(shouldRotate); - const filterSelectedTooltipValues = ( - tooltipSelectedValues: Array< - TooltipValue, XYChartSeriesIdentifier> - > - ) => { - const layerIndexes: number[] = []; - tooltipSelectedValues.forEach((v) => { - const index = dataLayers.findIndex((l) => - v.seriesIdentifier.seriesKeys.some((key: string | number) => - l.accessors.some( - (accessor) => getAccessorByDimension(accessor, l.table.columns) === key.toString() - ) - ) - ); - if (!layerIndexes.includes(index) && index !== -1) { - layerIndexes.push(index); - } - }); - - if (!layerIndexes.length) return; - layerIndexes.forEach((layerIndex) => { - const layer = dataLayers[layerIndex]; - const { table } = layer; - - if (layer.splitAccessors?.length !== 1) return; - - const splitAccessor = getAccessorByDimension(layer.splitAccessors[0], table.columns); - const filterValues = tooltipSelectedValues - .map((v) => v.datum?.[splitAccessor]) - .filter(nonNullable); - - const splitPoints = filterValues - .map((v) => - createSplitPoint(splitAccessor, v, formattedDatatables[layer.layerId].table.rows, table) - ) - .filter(nonNullable); - if (splitPoints.length) { - onClickMultiValue({ - data: { - column: splitPoints[0].column, - value: splitPoints.map(({ value }) => value), - table, - }, - }); - } - }); - }; - const clickHandler: ElementClickListener = ([elementEvent]) => { // this cast is safe because we are rendering a cartesian chart const [xyGeometry, xySeries] = elementEvent as XYChartElementEvent; - const layerIndex = dataLayers.findIndex((l) => + const layer = dataLayers.find((l) => xySeries.seriesKeys.some((key: string | number) => l.accessors.some( (accessor) => getAccessorByDimension(accessor, l.table.columns) === key.toString() @@ -620,42 +548,19 @@ export function XYChart({ ) ); - if (layerIndex === -1) { + if (!layer) { return; } - - const layer = dataLayers[layerIndex]; const { table } = layer; - const xColumn = layer.xAccessor && getColumnByAccessor(layer.xAccessor, table.columns); - const xAccessor = layer.xAccessor - ? getAccessorByDimension(layer.xAccessor, table.columns) - : undefined; - - const xFormat = xColumn ? fieldFormats[layer.layerId].xAccessors[xColumn.id] : undefined; - const currentXFormatter = - xAccessor && formattedDatatables[layer.layerId]?.formattedColumns[xAccessor] && xColumn - ? formatFactory(xFormat) - : xAxisFormatter; - - const rowIndex = table.rows.findIndex((row) => { - if (xAccessor) { - if (formattedDatatables[layer.layerId]?.formattedColumns[xAccessor]) { - // stringify the value to compare with the chart value - return currentXFormatter.convert(row[xAccessor]) === xyGeometry.x; - } - return row[xAccessor] === xyGeometry.x; - } - }); - - const points = [ - { - row: rowIndex, - column: table.columns.findIndex((col) => col.id === xAccessor), - value: xAccessor ? table.rows[rowIndex][xAccessor] : xyGeometry.x, - table, - }, - ]; + const xSeriesPoint = getXSeriesPoint( + layer, + xyGeometry.x, + fieldFormats, + formattedDatatables, + xAxisFormatter, + formatFactory + ); const splitPoints: FilterEvent['data']['data'] = []; @@ -700,7 +605,7 @@ export function XYChart({ } const context: FilterEvent['data'] = { - data: [...points, ...splitPoints], + data: [xSeriesPoint, ...splitPoints], }; onClickValue(context); }; @@ -796,8 +701,6 @@ export function XYChart({ overflowX: 'hidden', position: uiState ? 'absolute' : 'relative', }); - // enable the tooltip actions only if there is at least one splitAccessor to the dataLayer - const hasTooltipActions = dataLayers.some((dataLayer) => dataLayer.splitAccessors) && interactive; const { theme: settingsThemeOverrides = {}, ...settingsOverrides } = getOverridesFor( overrides, @@ -844,25 +747,15 @@ export function XYChart({ ) : undefined } - actions={ - !args.detailedTooltip && hasTooltipActions - ? [ - { - disabled: (selected) => selected.length < 1, - label: (selected) => - selected.length === 0 - ? i18n.translate('expressionXY.tooltipActions.emptyFilterSelection', { - defaultMessage: 'Select at least one series to filter', - }) - : i18n.translate('expressionXY.tooltipActions.filterValues', { - defaultMessage: 'Filter {seriesNumber} series', - values: { seriesNumber: selected.length }, - }), - onSelect: filterSelectedTooltipValues, - }, - ] - : undefined - } + actions={getTooltipActions( + dataLayers, + onClickMultiValue, + fieldFormats, + formattedDatatables, + xAxisFormatter, + formatFactory, + interactive && !args.detailedTooltip + )} customTooltip={ args.detailedTooltip ? ({ header, values }) => ( diff --git a/src/plugins/chart_expressions/expression_xy/tsconfig.json b/src/plugins/chart_expressions/expression_xy/tsconfig.json index 7f2af7005070d..901b7eb0568c6 100644 --- a/src/plugins/chart_expressions/expression_xy/tsconfig.json +++ b/src/plugins/chart_expressions/expression_xy/tsconfig.json @@ -32,6 +32,8 @@ "@kbn/kibana-react-plugin", "@kbn/chart-expressions-common", "@kbn/event-annotation-common", + "@kbn/visualization-ui-components", + "@kbn/es-query", ], "exclude": [ "target/**/*", diff --git a/src/plugins/data/public/actions/filters/create_filters_from_multi_value_click.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_multi_value_click.test.ts index 804f898945e57..f138544065b82 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_multi_value_click.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_multi_value_click.test.ts @@ -11,50 +11,81 @@ import { dataPluginMock } from '../../mocks'; import { setIndexPatterns, setSearchService } from '../../services'; import { createFiltersFromMultiValueClickAction } from './create_filters_from_multi_value_click'; import { FieldFormatsGetConfigFn, BytesFormat } from '@kbn/field-formats-plugin/common'; +import { Datatable } from '@kbn/expressions-plugin/common'; +import { BooleanRelation, Filter } from '@kbn/es-query'; const mockField = { name: 'bytes', filterable: true, }; +let table: Pick; + describe('createFiltersFromMultiValueClickAction', () => { let dataPoints: Parameters[0]['data']; beforeEach(() => { - dataPoints = { - table: { - columns: [ - { - name: 'test', - id: '1-1', - meta: { - type: 'date', - source: 'esaggs', - sourceParams: { - indexPatternId: 'logstash-*', - type: 'histogram', - params: { - field: 'bytes', - interval: 30, - otherBucket: true, - }, + table = { + columns: [ + { + name: 'test', + id: '1-1', + meta: { + type: 'date', + source: 'esaggs', + sourceParams: { + indexPatternId: 'logstash-*', + type: 'histogram', + params: { + field: 'bytes', + interval: 30, + otherBucket: true, }, }, }, - ], - rows: [ - { - '1-1': '2048', + }, + { + name: 'avg', + id: '2-2', + meta: { + type: 'number', + source: 'esaggs', + sourceParams: { + indexPatternId: 'logstash-*', + type: 'average', + params: { + field: 'bytes', + }, + }, }, - ], - meta: { - source: 'dataview-1', - type: 'esaggs', }, + ], + rows: [ + { + '1-1': 1691189380, + '2-2': 2048, + }, + { + '1-1': 1691189680, + '2-2': 90, + }, + ], + meta: { + source: 'dataview-1', + type: 'esaggs', }, - column: 0, - value: ['2048'], }; + dataPoints = [ + { + table, + cells: [ + { + column: 0, + row: 0, + }, + ], + }, + ]; const dataStart = dataPluginMock.createStartContract(); setSearchService(dataStart.search); @@ -72,30 +103,117 @@ describe('createFiltersFromMultiValueClickAction', () => { }); test('ignores event when value for rows is not provided', async () => { - dataPoints.table.rows[0]['1-1'] = null; + dataPoints[0].table.rows[0]['1-1'] = null; const filters = await createFiltersFromMultiValueClickAction({ data: dataPoints }); expect(filters).toBeUndefined(); }); test('ignores event when dataview id is not provided', async () => { - dataPoints.table.meta = undefined; + dataPoints[0].table.meta = undefined; const filters = await createFiltersFromMultiValueClickAction({ data: dataPoints }); expect(filters).toBeUndefined(); }); test('handles an event when aggregations type is a terms', async () => { - (dataPoints.table.columns[0].meta.sourceParams as any).type = 'terms'; - const filters = await createFiltersFromMultiValueClickAction({ data: dataPoints }); + (dataPoints[0].table.columns[0].meta.sourceParams as any).type = 'terms'; + const filters = (await createFiltersFromMultiValueClickAction({ + data: dataPoints, + })) as Filter[]; - expect(filters?.query?.match_phrase?.bytes).toEqual('2048'); + expect(filters[0]?.query?.match_phrase?.bytes).toEqual(1691189380); }); test('handles an event when aggregations type is not terms', async () => { - const filters = await createFiltersFromMultiValueClickAction({ data: dataPoints }); + const filters = (await createFiltersFromMultiValueClickAction({ + data: dataPoints, + })) as Filter[]; - expect(filters?.query?.range.bytes.gte).toEqual(2048); - expect(filters?.query?.range.bytes.lt).toEqual(2078); + expect(filters[0]?.query?.range.bytes.gte).toEqual(1691189380); + expect(filters[0]?.query?.range.bytes.lt).toEqual(1691189410); + }); + test('creates combined filters if relation is passed', async () => { + dataPoints[0].cells = [ + { + column: 0, + row: 0, + }, + { + column: 0, + row: 1, + }, + ]; + dataPoints[0].relation = BooleanRelation.OR; + const filters = (await createFiltersFromMultiValueClickAction({ + data: dataPoints, + })) as Filter[]; + expect(filters.length).toEqual(1); + expect(filters[0]?.meta.type).toEqual('combined'); + }); + test('creates separate filters if relation is not passed', async () => { + dataPoints[0].cells = [ + { + column: 0, + row: 0, + }, + { + column: 0, + row: 1, + }, + ]; + const filters = (await createFiltersFromMultiValueClickAction({ + data: dataPoints, + })) as Filter[]; + expect(filters.length).toEqual(2); + }); + test('creates separate filters for multiple tables', async () => { + dataPoints = [ + { + table, + cells: [ + { + column: 0, + row: 0, + }, + ], + }, + { + table, + cells: [ + { + column: 0, + row: 1, + }, + ], + }, + ]; + const filters = (await createFiltersFromMultiValueClickAction({ + data: dataPoints, + })) as Filter[]; + expect(filters.length).toEqual(2); + }); + test('doesnt combine duplicate filters', async () => { + dataPoints = [ + { + table, + cells: [ + { + column: 0, + row: 0, + }, + { + column: 0, + row: 0, + }, + ], + relation: BooleanRelation.OR, + }, + ]; + const filters = (await createFiltersFromMultiValueClickAction({ + data: dataPoints, + })) as Filter[]; + expect(filters.length).toEqual(1); + expect(filters[0]?.meta?.type).toEqual('range'); }); }); diff --git a/src/plugins/data/public/actions/filters/create_filters_from_multi_value_click.ts b/src/plugins/data/public/actions/filters/create_filters_from_multi_value_click.ts index b33f994015cfe..5bce14cedf1cd 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_multi_value_click.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_multi_value_click.ts @@ -5,68 +5,77 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { buildCombinedFilter, Filter, toggleFilterNegated, BooleanRelation } from '@kbn/es-query'; +import { + buildCombinedFilter, + toggleFilterNegated, + Filter, + compareFilters, + COMPARE_ALL_OPTIONS, +} from '@kbn/es-query'; +import { Truthy, uniqWith } from 'lodash'; import { createFilter } from './create_filters_from_value_click'; import type { MultiValueClickContext } from '../multi_value_click_action'; +import { mapAndFlattenFilters } from '../../query'; type MultiValueClickDataContext = MultiValueClickContext['data']; +export const truthy = (value: T): value is Truthy => !!value; + /** @public */ export const createFiltersFromMultiValueClickAction = async ({ data, negate, -}: MultiValueClickDataContext) => { - const { table, column, value } = data; - const dataViewId = table?.meta?.source; - if (!dataViewId) return; - - const columnId = table.columns[column].id; +}: MultiValueClickDataContext): Promise => { + if (!data || data.length === 0) return; - const filters = ( + const result = ( await Promise.all( - value.map(async (v) => { - return ( - await createFilter( - table, - column, - table.rows.findIndex((r) => r[columnId] === v) + data.map(async (d) => { + const { table, cells, relation } = d; + const dataViewId = table?.meta?.source; + if (!dataViewId) return; + + const filters = ( + await Promise.all( + cells.map(async ({ column, row }) => await createFilter(table, column, row)) ) - )?.[0]; + ) + .flat() + .filter(truthy); + + const uniqueFilters = uniqWith(mapAndFlattenFilters(filters), (a, b) => + compareFilters(a, b, COMPARE_ALL_OPTIONS) + ); + + if (uniqueFilters.length === 0) return; + + if (uniqueFilters.length === 1) { + return negate ? [toggleFilterNegated(uniqueFilters[0])] : uniqueFilters; + } + + if (!relation) { + return negate ? uniqueFilters.map((f) => toggleFilterNegated(f)) : uniqueFilters; + } + + const filtersHaveAlias = uniqueFilters.every((f) => f.meta.alias); + const alias = filtersHaveAlias + ? uniqueFilters.map((f) => f.meta.alias).join(` ${relation} `) + : ''; + + return buildCombinedFilter( + relation, + uniqueFilters, + { id: dataViewId }, + undefined, + negate, + alias + ); }) ) - ).filter(Boolean) as Filter[]; - if (filters.length === 0) return; - // no need for combined filter in case of one filter - if (filters.length === 1) { - if (filters[0] && negate) { - return toggleFilterNegated(filters[0]); - } - return filters[0]; - } - const filtersHaveAlias = filters.every((f) => f.meta.alias); - let alias = ''; - if (filtersHaveAlias) { - filters.forEach((f, i) => { - if (i === filters.length - 1) { - alias += `${f.meta.alias}`; - } else { - alias += `${f.meta.alias} ${BooleanRelation.OR} `; - } - }); - } - let filter: Filter = buildCombinedFilter( - BooleanRelation.OR, - filters, - { - id: dataViewId, - }, - undefined, - undefined, - alias - ); - if (filter && negate) { - filter = toggleFilterNegated(filter); - } + ) + .flat() + .filter(truthy); - return filter; + if (result.length === 0) return; + return result; }; diff --git a/src/plugins/data/public/actions/multi_value_click_action.ts b/src/plugins/data/public/actions/multi_value_click_action.ts index 422b1d8653e02..1f9059ae5e866 100644 --- a/src/plugins/data/public/actions/multi_value_click_action.ts +++ b/src/plugins/data/public/actions/multi_value_click_action.ts @@ -6,10 +6,10 @@ * Side Public License, v 1. */ -import type { Filter } from '@kbn/es-query'; import { Datatable } from '@kbn/expressions-plugin/public'; import { UiActionsActionDefinition } from '@kbn/ui-actions-plugin/public'; -import { FilterManager } from '../query'; +import { BooleanRelation, extractTimeFilter, convertRangeFilterToTimeRange } from '@kbn/es-query'; +import { QueryStart } from '../query'; import { createFiltersFromMultiValueClickAction } from './filters/create_filters_from_multi_value_click'; export type MultiValueClickActionContext = MultiValueClickContext; @@ -20,18 +20,21 @@ export interface MultiValueClickContext { // Apps using this property will need to cast to `IEmbeddable`. embeddable?: unknown; data: { - data: { + data: Array<{ + cells: Array<{ + column: number; + row: number; + }>; table: Pick; - column: number; - value: any[]; - }; + relation?: BooleanRelation; + }>; timeFieldName?: string; negate?: boolean; }; } export function createMultiValueClickActionDefinition( - getStartServices: () => { filterManager: FilterManager } + getStartServices: () => { query: QueryStart } ): UiActionsActionDefinition { return { type: ACTION_MULTI_VALUE_CLICK, @@ -41,9 +44,23 @@ export function createMultiValueClickActionDefinition( const filters = await createFiltersFromMultiValueClickAction(context.data); return Boolean(filters); }, - execute: async (context: MultiValueClickActionContext) => { - const filter = (await createFiltersFromMultiValueClickAction(context.data)) as Filter; - getStartServices().filterManager.addFilters(filter); + execute: async ({ data }: MultiValueClickActionContext) => { + const filters = await createFiltersFromMultiValueClickAction(data); + if (!filters || filters?.length === 0) return; + const { + filterManager, + timefilter: { timefilter }, + } = getStartServices().query; + + if (data.timeFieldName) { + const { timeRangeFilter, restOfFilters } = extractTimeFilter(data.timeFieldName, filters); + filterManager.addFilters(restOfFilters); + if (timeRangeFilter) { + timefilter.setTime(convertRangeFilterToTimeRange(timeRangeFilter)); + } + } else { + filterManager.addFilters(filters); + } }, }; } diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 02d5e7f69ad51..8f4e37afb29b2 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -158,7 +158,7 @@ export class DataPublicPlugin uiActions.addTriggerAction( 'MULTI_VALUE_CLICK_TRIGGER', createMultiValueClickActionDefinition(() => ({ - filterManager: query.filterManager, + query, })) ); diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts index 94c09c2d79376..dbafad289c006 100644 --- a/src/plugins/embeddable/public/lib/triggers/triggers.ts +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n'; import { Datatable, DatatableColumnMeta } from '@kbn/expressions-plugin/common'; import { Trigger, RowClickContext } from '@kbn/ui-actions-plugin/public'; +import { BooleanRelation } from '@kbn/es-query'; import { IEmbeddable } from '..'; export interface EmbeddableContext { @@ -32,11 +33,14 @@ export interface ValueClickContext { export interface MultiValueClickContext { embeddable?: T; data: { - data: { + data: Array<{ table: Pick; - column: number; - value: any[]; - }; + cells: Array<{ + column: number; + row: number; + }>; + relation?: BooleanRelation; + }>; timeFieldName?: string; negate?: boolean; }; @@ -157,12 +161,27 @@ export const cellValueTrigger: Trigger = { export const isValueClickTriggerContext = ( context: ChartActionContext -): context is ValueClickContext => context.data && 'data' in context.data; +): context is ValueClickContext => { + return ( + context.data && + 'data' in context.data && + Array.isArray(context.data.data) && + context.data.data.length > 0 && + 'column' in context.data.data[0] + ); +}; export const isMultiValueClickTriggerContext = ( context: ChartActionContext -): context is MultiValueClickContext => - context.data && 'data' in context.data && !Array.isArray(context.data.data); +): context is MultiValueClickContext => { + return ( + context.data && + 'data' in context.data && + Array.isArray(context.data.data) && + context.data.data.length > 0 && + 'cells' in context.data.data[0] + ); +}; export const isRangeSelectTriggerContext = ( context: ChartActionContext diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx index 18d0833ed4250..6514e13d65a11 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx @@ -530,7 +530,9 @@ describe('workspace_panel', () => { const onEvent = expressionRendererMock.mock.calls[0][0].onEvent!; - const eventData = { myData: true, table: { rows: [], columns: [] }, column: 0 }; + const eventData = { + data: [{ table: { rows: [], columns: [] }, cells: [{ column: 0, row: 0 }] }], + }; onEvent({ name: 'multiFilter', data: eventData }); expect(uiActionsMock.getTrigger).toHaveBeenCalledWith(VIS_EVENT_TO_TRIGGER.multiFilter); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index 3f92236c99e5d..02db9e18919f7 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -434,7 +434,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ plugins.uiActions.getTrigger(VIS_EVENT_TO_TRIGGER[event.name]).exec({ data: { ...event.data, - timeFieldName: inferTimeField(plugins.data.datatableUtilities, event.data), + timeFieldName: inferTimeField(plugins.data.datatableUtilities, event), }, }); } @@ -442,7 +442,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ plugins.uiActions.getTrigger(VIS_EVENT_TO_TRIGGER[event.name]).exec({ data: { ...event.data, - timeFieldName: inferTimeField(plugins.data.datatableUtilities, event.data), + timeFieldName: inferTimeField(plugins.data.datatableUtilities, event), }, }); } diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx index 8741d73a4a7b4..67dea2f98231c 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.tsx @@ -1227,45 +1227,35 @@ export class Embeddable if (!this.deps.getTrigger || this.input.disableTriggers) { return; } + + let eventHandler: + | LensBaseEmbeddableInput['onBrushEnd'] + | LensBaseEmbeddableInput['onFilter'] + | LensBaseEmbeddableInput['onTableRowClick']; + let shouldExecuteDefaultTriggers = true; + if (isLensBrushEvent(event)) { - let shouldExecuteDefaultTriggers = true; - if (this.input.onBrushEnd) { - this.input.onBrushEnd({ - ...event.data, - preventDefault: () => { - shouldExecuteDefaultTriggers = false; - }, - }); - } - if (shouldExecuteDefaultTriggers) { - this.deps.getTrigger(VIS_EVENT_TO_TRIGGER[event.name]).exec({ - data: { - ...event.data, - timeFieldName: - event.data.timeFieldName || - inferTimeField(this.deps.data.datatableUtilities, event.data), - }, - embeddable: this, - }); - } + eventHandler = this.input.onBrushEnd; + } else if (isLensFilterEvent(event) || isLensMultiFilterEvent(event)) { + eventHandler = this.input.onFilter; + } else if (isLensTableRowContextMenuClickEvent(event)) { + eventHandler = this.input.onTableRowClick; } - if (isLensFilterEvent(event) || isLensMultiFilterEvent(event)) { - let shouldExecuteDefaultTriggers = true; - if (this.input.onFilter) { - this.input.onFilter({ - ...event.data, - preventDefault: () => { - shouldExecuteDefaultTriggers = false; - }, - }); - } + + eventHandler?.({ + ...event.data, + preventDefault: () => { + shouldExecuteDefaultTriggers = false; + }, + }); + + if (isLensFilterEvent(event) || isLensMultiFilterEvent(event) || isLensBrushEvent(event)) { if (shouldExecuteDefaultTriggers) { this.deps.getTrigger(VIS_EVENT_TO_TRIGGER[event.name]).exec({ data: { ...event.data, timeFieldName: - event.data.timeFieldName || - inferTimeField(this.deps.data.datatableUtilities, event.data), + event.data.timeFieldName || inferTimeField(this.deps.data.datatableUtilities, event), }, embeddable: this, }); @@ -1273,15 +1263,6 @@ export class Embeddable } if (isLensTableRowContextMenuClickEvent(event)) { - let shouldExecuteDefaultTriggers = true; - if (this.input.onTableRowClick) { - this.input.onTableRowClick({ - ...event.data, - preventDefault: () => { - shouldExecuteDefaultTriggers = false; - }, - }); - } if (shouldExecuteDefaultTriggers) { this.deps.getTrigger(VIS_EVENT_TO_TRIGGER[event.name]).exec( { diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 3b989366fa307..8b69929b4fb84 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -1331,6 +1331,12 @@ export interface LensTableRowContextMenuEvent { data: RowClickContext['data']; } +export type TriggerEvent = + | BrushTriggerEvent + | ClickTriggerEvent + | MultiClickTriggerEvent + | LensTableRowContextMenuEvent; + export function isLensFilterEvent(event: ExpressionRendererEvent): event is ClickTriggerEvent { return event.name === 'filter'; } diff --git a/x-pack/plugins/lens/public/utils.test.ts b/x-pack/plugins/lens/public/utils.test.ts index 52e509557b2fc..e775059586aff 100644 --- a/x-pack/plugins/lens/public/utils.test.ts +++ b/x-pack/plugins/lens/public/utils.test.ts @@ -56,9 +56,12 @@ describe('utils', () => { test('infer time field for brush event', () => { expect( inferTimeField(datatableUtilities, { - table, - column: 0, - range: [1, 2], + name: 'brush', + data: { + table, + column: 0, + range: [1, 2], + }, }) ).toEqual('abc'); }); @@ -66,9 +69,12 @@ describe('utils', () => { test('do not return time field if time range is not bound', () => { expect( inferTimeField(datatableUtilities, { - table: tableWithoutAppliedTimeRange, - column: 0, - range: [1, 2], + name: 'brush', + data: { + table: tableWithoutAppliedTimeRange, + column: 0, + range: [1, 2], + }, }) ).toEqual(undefined); }); @@ -76,14 +82,17 @@ describe('utils', () => { test('infer time field for click event', () => { expect( inferTimeField(datatableUtilities, { - data: [ - { - table, - column: 0, - row: 0, - value: 1, - }, - ], + name: 'filter', + data: { + data: [ + { + table, + column: 0, + row: 0, + value: 1, + }, + ], + }, }) ).toEqual('abc'); }); @@ -91,15 +100,18 @@ describe('utils', () => { test('do not return time field for negated click event', () => { expect( inferTimeField(datatableUtilities, { - data: [ - { - table, - column: 0, - row: 0, - value: 1, - }, - ], - negate: true, + name: 'filter', + data: { + data: [ + { + table, + column: 0, + row: 0, + value: 1, + }, + ], + negate: true, + }, }) ).toEqual(undefined); }); @@ -107,14 +119,17 @@ describe('utils', () => { test('do not return time field for click event without bound time field', () => { expect( inferTimeField(datatableUtilities, { - data: [ - { - table: tableWithoutAppliedTimeRange, - column: 0, - row: 0, - value: 1, - }, - ], + name: 'filter', + data: { + data: [ + { + table: tableWithoutAppliedTimeRange, + column: 0, + row: 0, + value: 1, + }, + ], + }, }) ).toEqual(undefined); }); diff --git a/x-pack/plugins/lens/public/utils.ts b/x-pack/plugins/lens/public/utils.ts index 446d7aac37e66..b1deface2cd77 100644 --- a/x-pack/plugins/lens/public/utils.ts +++ b/x-pack/plugins/lens/public/utils.ts @@ -14,11 +14,6 @@ import type { TimefilterContract } from '@kbn/data-plugin/public'; import type { IUiSettingsClient, SavedObjectReference } from '@kbn/core/public'; import type { DataView, DataViewsContract } from '@kbn/data-views-plugin/public'; import type { DatatableUtilitiesService } from '@kbn/data-plugin/common'; -import { - BrushTriggerEvent, - ClickTriggerEvent, - MultiClickTriggerEvent, -} from '@kbn/charts-plugin/public'; import { emptyTitleText } from '@kbn/visualization-ui-components'; import { RequestAdapter } from '@kbn/inspector-plugin/common'; import { ISearchStart } from '@kbn/data-plugin/public'; @@ -34,6 +29,10 @@ import { DragDropOperation, isOperation, UserMessage, + TriggerEvent, + isLensBrushEvent, + isLensMultiFilterEvent, + isLensFilterEvent, } from './types'; import type { DatasourceStates, VisualizationState } from './state_management'; import type { IndexPatternServiceAPI } from './data_views_service/service'; @@ -214,17 +213,28 @@ export function getRemoveOperation( return layerCount === 1 ? 'clear' : 'remove'; } -export function inferTimeField( - datatableUtilities: DatatableUtilitiesService, - context: BrushTriggerEvent['data'] | ClickTriggerEvent['data'] | MultiClickTriggerEvent['data'] -) { - const tablesAndColumns = - 'table' in context - ? [{ table: context.table, column: context.column }] - : !context.negate - ? context.data - : // if it's a negated filter, never respect bound time field - []; +function getTablesAndColumnsFromContext(event: TriggerEvent) { + // if it's a negated filter, never respect bound time field + if ('negate' in event.data && event.data.negate) { + return []; + } + if (isLensBrushEvent(event)) { + return [{ table: event.data.table, column: event.data.column }]; + } + if (isLensMultiFilterEvent(event)) { + return event.data.data.map(({ table, cells }) => ({ + table, + column: cells[0].column, + })); + } + if (isLensFilterEvent(event)) { + return event.data.data; + } + return event.data; +} + +export function inferTimeField(datatableUtilities: DatatableUtilitiesService, event: TriggerEvent) { + const tablesAndColumns = getTablesAndColumnsFromContext(event); return !Array.isArray(tablesAndColumns) ? [tablesAndColumns] : tablesAndColumns diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx index eadf94552794e..943bf4dab0d80 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx @@ -187,7 +187,7 @@ const LensEmbeddableComponent: React.FC = ({ const onFilterCallback = useCallback( async (e: ClickTriggerEvent['data'] | MultiClickTriggerEvent['data']) => { - if (!Array.isArray(e.data) || preferredSeriesType !== 'area') { + if (!isClickTriggerEvent(e) || preferredSeriesType !== 'area') { return; } // Update timerange when clicking on a dot in an area chart @@ -301,4 +301,10 @@ const LensEmbeddableComponent: React.FC = ({ ); }; +const isClickTriggerEvent = ( + e: ClickTriggerEvent['data'] | MultiClickTriggerEvent['data'] +): e is ClickTriggerEvent['data'] => { + return Array.isArray(e.data) && 'column' in e.data[0]; +}; + export const LensEmbeddable = React.memo(LensEmbeddableComponent); diff --git a/x-pack/test/functional/apps/lens/group4/dashboard.ts b/x-pack/test/functional/apps/lens/group4/dashboard.ts index daa8a750ad1c8..e94f935323235 100644 --- a/x-pack/test/functional/apps/lens/group4/dashboard.ts +++ b/x-pack/test/functional/apps/lens/group4/dashboard.ts @@ -107,9 +107,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await retry.try(async () => { // show the tooltip actions await rightClickInChart(30, 5); // hardcoded position of bar, depends heavy on data and charts implementation - await (await find.byCssSelector('.echTooltipActions__action')).click(); + await (await find.allByCssSelector('.echTooltipActions__action'))[1].click(); const hasIpFilter = await filterBar.hasFilter('ip', '97.220.3.248'); expect(hasIpFilter).to.be(true); + await rightClickInChart(35, 5); // hardcoded position of bar, depends heavy on data and charts implementation + await (await find.allByCssSelector('.echTooltipActions__action'))[0].click(); + const time = await PageObjects.timePicker.getTimeConfig(); + expect(time.start).to.equal('Sep 21, 2015 @ 09:00:00.000'); + expect(time.end).to.equal('Sep 21, 2015 @ 12:00:00.000'); }); }); From c04f5661d354e36940e73f4095d7bed38f3bde17 Mon Sep 17 00:00:00 2001 From: Carlos Crespo Date: Wed, 9 Aug 2023 17:06:37 +0200 Subject: [PATCH 09/22] [Infra UI] Centralize chart components (#163283) closes [#161957](https://github.com/elastic/kibana/issues/161957) ## Summary This PR encapsulates the styling and logic to render the Lens charts components. Doing so simplifies the usage in places that render these charts, eliminating the previously necessary code duplication ### How to test - Start a local Kibana instance - Navigate to `Infrastructure` > `Hosts` - Confirm that all charts still work - Play with the filters - Verify whether only charts above the fold are rendered - Open the flyout - Switch hosts with the flyout open --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../lens/dashboards/host/kpi_grid_config.ts | 35 ++-- .../components/asset_details/constants.ts | 8 + .../tabs/overview/kpis/kpi_grid.tsx | 60 +++++-- .../asset_details/tabs/overview/kpis/tile.tsx | 124 -------------- .../tabs/overview/metrics/metric_chart.tsx | 116 ------------- .../tabs/overview/metrics/metrics_grid.tsx | 92 +++++++--- .../components/lens/chart_load_error.tsx | 38 +++++ .../components/lens/chart_placeholder.tsx | 3 +- .../infra/public/components/lens/index.tsx | 3 +- .../public/components/lens/lens_chart.tsx | 110 ++++++++++++ .../public/components/lens/lens_wrapper.tsx | 36 ++-- .../metric_explanation/tooltip_content.tsx | 4 +- .../infra/public/components/lens/types.ts | 27 +++ .../infra/public/hooks/use_lens_attributes.ts | 4 +- .../components/chart/metric_chart_wrapper.tsx | 27 +-- .../hosts/components/kpis/hosts_tile.tsx | 12 +- .../hosts/components/kpis/kpi_grid.tsx | 16 +- .../metrics/hosts/components/kpis/tile.tsx | 157 +++++------------- .../components/tabs/metrics/metric_chart.tsx | 138 ++++----------- .../public/pages/metrics/hosts/constants.ts | 3 +- .../translations/translations/fr-FR.json | 16 +- .../translations/translations/ja-JP.json | 16 +- .../translations/translations/zh-CN.json | 16 +- .../page_objects/infra_hosts_view.ts | 4 +- 24 files changed, 472 insertions(+), 593 deletions(-) create mode 100644 x-pack/plugins/infra/public/components/asset_details/constants.ts delete mode 100644 x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/tile.tsx delete mode 100644 x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metric_chart.tsx create mode 100644 x-pack/plugins/infra/public/components/lens/chart_load_error.tsx create mode 100644 x-pack/plugins/infra/public/components/lens/lens_chart.tsx create mode 100644 x-pack/plugins/infra/public/components/lens/types.ts diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/host/kpi_grid_config.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/host/kpi_grid_config.ts index cc4f51c8f2d18..9dde33f39cbdf 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/host/kpi_grid_config.ts +++ b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/host/kpi_grid_config.ts @@ -5,16 +5,24 @@ * 2.0. */ -import { TypedLensByValueInput } from '@kbn/lens-plugin/public'; import { i18n } from '@kbn/i18n'; -import { Layer } from '../../../../../hooks/use_lens_attributes'; +import type { TypedLensByValueInput } from '@kbn/lens-plugin/public'; +import type { Layer } from '../../../../../hooks/use_lens_attributes'; import { hostLensFormulas } from '../../../constants'; -import { FormulaConfig } from '../../../types'; import { TOOLTIP } from './translations'; -import { MetricLayerOptions } from '../../visualization_types/layers'; -export interface KPIChartProps - extends Pick { +import type { FormulaConfig } from '../../../types'; +import type { MetricLayerOptions } from '../../visualization_types'; + +export const KPI_CHART_HEIGHT = 150; +export const AVERAGE_SUBTITLE = i18n.translate( + 'xpack.infra.assetDetailsEmbeddable.overview.kpi.subtitle.average', + { + defaultMessage: 'Average', + } +); + +export interface KPIChartProps extends Pick { layers: Layer; toolTip: string; } @@ -22,7 +30,7 @@ export interface KPIChartProps export const KPI_CHARTS: KPIChartProps[] = [ { id: 'cpuUsage', - title: i18n.translate('xpack.infra.hostsViewPage.metricTrend.cpuUsage.title', { + title: i18n.translate('xpack.infra.assetDetailsEmbeddable.overview.kpi.cpuUsage.title', { defaultMessage: 'CPU Usage', }), layers: { @@ -45,9 +53,12 @@ export const KPI_CHARTS: KPIChartProps[] = [ }, { id: 'normalizedLoad1m', - title: i18n.translate('xpack.infra.hostsViewPage.metricTrend.normalizedLoad1m.title', { - defaultMessage: 'CPU Usage', - }), + title: i18n.translate( + 'xpack.infra.assetDetailsEmbeddable.overview.kpi.normalizedLoad1m.title', + { + defaultMessage: 'CPU Usage', + } + ), layers: { data: { ...hostLensFormulas.normalizedLoad1m, @@ -68,7 +79,7 @@ export const KPI_CHARTS: KPIChartProps[] = [ }, { id: 'memoryUsage', - title: i18n.translate('xpack.infra.hostsViewPage.metricTrend.memoryUsage.title', { + title: i18n.translate('xpack.infra.assetDetailsEmbeddable.overview.kpi.memoryUsage.title', { defaultMessage: 'CPU Usage', }), layers: { @@ -91,7 +102,7 @@ export const KPI_CHARTS: KPIChartProps[] = [ }, { id: 'diskSpaceUsage', - title: i18n.translate('xpack.infra.hostsViewPage.metricTrend.diskSpaceUsage.title', { + title: i18n.translate('xpack.infra.assetDetailsEmbeddable.overview.kpi.diskSpaceUsage.title', { defaultMessage: 'CPU Usage', }), layers: { diff --git a/x-pack/plugins/infra/public/components/asset_details/constants.ts b/x-pack/plugins/infra/public/components/asset_details/constants.ts new file mode 100644 index 0000000000000..546e2b9aad4d9 --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/constants.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const METRIC_CHART_HEIGHT = 300; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi_grid.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi_grid.tsx index b86201a29098c..c134f0de6bb7a 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi_grid.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi_grid.tsx @@ -4,21 +4,55 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; + +import React, { useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { Tile, type TileProps } from './tile'; -import { KPI_CHARTS } from '../../../../../common/visualizations/lens/dashboards/host/kpi_grid_config'; +import type { DataView } from '@kbn/data-views-plugin/public'; +import type { TimeRange } from '@kbn/es-query'; +import { LensChart, TooltipContent } from '../../../../lens'; +import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; +import { + KPI_CHARTS, + KPI_CHART_HEIGHT, + AVERAGE_SUBTITLE, +} from '../../../../../common/visualizations/lens/dashboards/host/kpi_grid_config'; + +interface Props { + dataView?: DataView; + nodeName: string; + timeRange: TimeRange; +} + +export const KPIGrid = React.memo(({ nodeName, dataView, timeRange }: Props) => { + const filters = useMemo(() => { + return [ + buildCombinedHostsFilter({ + field: 'host.name', + values: [nodeName], + dataView, + }), + ]; + }, [dataView, nodeName]); -export const KPIGrid = React.memo(({ nodeName, dataView, timeRange: dateRange }: TileProps) => { return ( - <> - - {KPI_CHARTS.map((chartProp, index) => ( - - - - ))} - - + + {KPI_CHARTS.map(({ id, layers, title, toolTip }, index) => ( + + } + visualizationType="lnsMetric" + disableTriggers + hidePanelTitles + /> + + ))} + ); }); diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/tile.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/tile.tsx deleted file mode 100644 index 9907b81d64fc0..0000000000000 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/tile.tsx +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React, { useMemo } from 'react'; -import type { DataView } from '@kbn/data-views-plugin/public'; -import { i18n } from '@kbn/i18n'; -import { EuiIcon, EuiPanel, EuiFlexGroup, EuiFlexItem, EuiText, EuiToolTip } from '@elastic/eui'; -import styled from 'styled-components'; -import type { Action } from '@kbn/ui-actions-plugin/public'; -import { TimeRange } from '@kbn/es-query'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { LensWrapper, TooltipContent } from '../../../../lens'; -import type { KPIChartProps } from '../../../../../common/visualizations/lens/dashboards/host/kpi_grid_config'; -import { useLensAttributes } from '../../../../../hooks/use_lens_attributes'; -import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; - -const MIN_HEIGHT = 150; - -export interface TileProps { - timeRange: TimeRange; - dataView?: DataView; - nodeName: string; -} - -export const Tile = ({ - id, - layers, - title, - toolTip, - dataView, - nodeName, - timeRange, -}: KPIChartProps & TileProps) => { - const getSubtitle = () => - i18n.translate('xpack.infra.assetDetailsEmbeddable.overview.metricTrend.subtitle.average', { - defaultMessage: 'Average', - }); - - const { formula, attributes, getExtraActions, error } = useLensAttributes({ - dataView, - title, - layers: { ...layers, options: { ...layers.options, subtitle: getSubtitle() } }, - visualizationType: 'lnsMetric', - }); - - const filters = useMemo(() => { - return [ - buildCombinedHostsFilter({ - field: 'host.name', - values: [nodeName], - dataView, - }), - ]; - }, [dataView, nodeName]); - - const extraActions: Action[] = useMemo( - () => - getExtraActions({ - timeRange, - filters, - }), - [filters, getExtraActions, timeRange] - ); - - const loading = !attributes; - - return ( - - {error ? ( - - - - - - - - - - - ) : ( - } - anchorClassName="eui-fullWidth" - > - - - )} - - ); -}; - -const EuiPanelStyled = styled(EuiPanel)` - min-height: ${MIN_HEIGHT}px; - .echMetric { - border-radius: ${({ theme }) => theme.eui.euiBorderRadius}; - pointer-events: none; - } -`; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metric_chart.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metric_chart.tsx deleted file mode 100644 index ad75734013a29..0000000000000 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metric_chart.tsx +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React, { useMemo } from 'react'; -import { Action } from '@kbn/ui-actions-plugin/public'; -import { EuiIcon, EuiPanel, EuiFlexGroup, EuiFlexItem, EuiText, useEuiTheme } from '@elastic/eui'; -import { css } from '@emotion/react'; -import { TypedLensByValueInput } from '@kbn/lens-plugin/public'; -import type { DataView } from '@kbn/data-views-plugin/public'; -import type { TimeRange } from '@kbn/es-query'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { LensWrapper } from '../../../../lens/lens_wrapper'; -import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; -import { useLensAttributes, type Layer } from '../../../../../hooks/use_lens_attributes'; -import type { FormulaConfig, XYLayerOptions } from '../../../../../common/visualizations'; - -export interface MetricChartProps extends Pick { - title: string; - layers: Array>; - dataView?: DataView; - timeRange: TimeRange; - nodeName: string; -} - -const MIN_HEIGHT = 250; - -export const MetricChart = ({ - id, - title, - layers, - nodeName, - timeRange, - dataView, - overrides, -}: MetricChartProps) => { - const { euiTheme } = useEuiTheme(); - - const { attributes, getExtraActions, error } = useLensAttributes({ - dataView, - layers, - title, - visualizationType: 'lnsXY', - }); - - const filters = useMemo(() => { - return [ - buildCombinedHostsFilter({ - field: 'host.name', - values: [nodeName], - dataView, - }), - ]; - }, [dataView, nodeName]); - - const extraActions: Action[] = useMemo( - () => - getExtraActions({ - timeRange, - filters, - }), - [timeRange, filters, getExtraActions] - ); - - const loading = !attributes; - - return ( - - {error ? ( - - - - - - - - - - - ) : ( - - )} - - ); -}; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx index 531b5aa4a4191..be96fe575d2be 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx @@ -4,18 +4,30 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; +import React, { useCallback } from 'react'; import { EuiFlexGrid, EuiFlexItem, EuiTitle, EuiSpacer, EuiFlexGroup } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import type { DataView } from '@kbn/data-views-plugin/public'; -import { TimeRange } from '@kbn/es-query'; +import type { TimeRange } from '@kbn/es-query'; import { FormattedMessage } from '@kbn/i18n-react'; -import { HostMetricsDocsLink } from '../../../../lens'; -import { MetricChart, type MetricChartProps } from './metric_chart'; -import { hostLensFormulas } from '../../../../../common/visualizations'; +import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; +import type { Layer } from '../../../../../hooks/use_lens_attributes'; +import { HostMetricsDocsLink, LensChart, type LensChartProps } from '../../../../lens'; +import { + type FormulaConfig, + hostLensFormulas, + type XYLayerOptions, +} from '../../../../../common/visualizations'; +import { METRIC_CHART_HEIGHT } from '../../../constants'; -const PERCENT_LEFT_AXIS: Pick['overrides'] = { +type DataViewOrigin = 'logs' | 'metrics'; +interface MetricChartConfig extends Pick { + layers: Array>; + toolTip: string; +} + +const PERCENT_LEFT_AXIS: Pick['overrides'] = { axisLeft: { domain: { min: 0, @@ -24,7 +36,7 @@ const PERCENT_LEFT_AXIS: Pick['overrides'] = { }, }; -const LEGEND_SETTINGS: Pick['overrides'] = { +const LEGEND_SETTINGS: Pick['overrides'] = { settings: { showLegend: true, legendPosition: 'bottom', @@ -33,8 +45,8 @@ const LEGEND_SETTINGS: Pick['overrides'] = { }; const CHARTS_IN_ORDER: Array< - Pick & { - dataViewType: 'logs' | 'metrics'; + Pick & { + dataViewOrigin: DataViewOrigin; } > = [ { @@ -49,7 +61,7 @@ const CHARTS_IN_ORDER: Array< layerType: 'data', }, ], - dataViewType: 'metrics', + dataViewOrigin: 'metrics', overrides: { axisLeft: PERCENT_LEFT_AXIS.axisLeft, }, @@ -65,7 +77,7 @@ const CHARTS_IN_ORDER: Array< layerType: 'data', }, ], - dataViewType: 'metrics', + dataViewOrigin: 'metrics', overrides: { axisLeft: PERCENT_LEFT_AXIS.axisLeft, }, @@ -96,7 +108,7 @@ const CHARTS_IN_ORDER: Array< layerType: 'referenceLine', }, ], - dataViewType: 'metrics', + dataViewOrigin: 'metrics', }, { id: 'logRate', @@ -109,7 +121,7 @@ const CHARTS_IN_ORDER: Array< layerType: 'data', }, ], - dataViewType: 'logs', + dataViewOrigin: 'logs', }, { id: 'diskSpaceUsageAvailable', @@ -152,7 +164,7 @@ const CHARTS_IN_ORDER: Array< axisLeft: PERCENT_LEFT_AXIS.axisLeft, settings: LEGEND_SETTINGS.settings, }, - dataViewType: 'metrics', + dataViewOrigin: 'metrics', }, { id: 'diskThroughputReadWrite', @@ -184,7 +196,7 @@ const CHARTS_IN_ORDER: Array< overrides: { settings: LEGEND_SETTINGS.settings, }, - dataViewType: 'metrics', + dataViewOrigin: 'metrics', }, { id: 'diskIOReadWrite', @@ -216,7 +228,7 @@ const CHARTS_IN_ORDER: Array< overrides: { settings: LEGEND_SETTINGS.settings, }, - dataViewType: 'metrics', + dataViewOrigin: 'metrics', }, { id: 'rxTx', @@ -248,7 +260,7 @@ const CHARTS_IN_ORDER: Array< overrides: { settings: LEGEND_SETTINGS.settings, }, - dataViewType: 'metrics', + dataViewOrigin: 'metrics', }, ]; @@ -259,8 +271,35 @@ export interface MetricsGridProps { logsDataView?: DataView; } +export interface MetricsGridProps { + nodeName: string; + timeRange: TimeRange; + metricsDataView?: DataView; + logsDataView?: DataView; +} + export const MetricsGrid = React.memo( ({ nodeName, metricsDataView, logsDataView, timeRange }: MetricsGridProps) => { + const getDataView = useCallback( + (dataViewOrigin: DataViewOrigin) => { + return dataViewOrigin === 'metrics' ? metricsDataView : logsDataView; + }, + [logsDataView, metricsDataView] + ); + + const getFilters = useCallback( + (dataViewOrigin: DataViewOrigin) => { + return [ + buildCombinedHostsFilter({ + field: 'host.name', + values: [nodeName], + dataView: getDataView(dataViewOrigin), + }), + ]; + }, + [getDataView, nodeName] + ); + return ( @@ -277,13 +316,20 @@ export const MetricsGrid = React.memo( - {CHARTS_IN_ORDER.map(({ dataViewType, ...chartProp }, index) => ( + {CHARTS_IN_ORDER.map(({ dataViewOrigin, id, layers, title, overrides }, index) => ( - ))} diff --git a/x-pack/plugins/infra/public/components/lens/chart_load_error.tsx b/x-pack/plugins/infra/public/components/lens/chart_load_error.tsx new file mode 100644 index 0000000000000..5ffdc573a2cd7 --- /dev/null +++ b/x-pack/plugins/infra/public/components/lens/chart_load_error.tsx @@ -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 React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { css } from '@emotion/react'; + +export const ChartLoadError = () => { + return ( + + + + + + + + + + + ); +}; diff --git a/x-pack/plugins/infra/public/components/lens/chart_placeholder.tsx b/x-pack/plugins/infra/public/components/lens/chart_placeholder.tsx index 7bf35f0e0392a..2dfcbfa21c814 100644 --- a/x-pack/plugins/infra/public/components/lens/chart_placeholder.tsx +++ b/x-pack/plugins/infra/public/components/lens/chart_placeholder.tsx @@ -6,8 +6,7 @@ */ import React from 'react'; -import { EuiFlexGroup, EuiProgress, EuiFlexItem, EuiLoadingChart } from '@elastic/eui'; -import { useEuiTheme } from '@elastic/eui'; +import { EuiFlexGroup, EuiProgress, EuiFlexItem, EuiLoadingChart, useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/react'; export const ChartLoadingProgress = ({ hasTopMargin = false }: { hasTopMargin?: boolean }) => { diff --git a/x-pack/plugins/infra/public/components/lens/index.tsx b/x-pack/plugins/infra/public/components/lens/index.tsx index 17a2f5b480442..93d050209a219 100644 --- a/x-pack/plugins/infra/public/components/lens/index.tsx +++ b/x-pack/plugins/infra/public/components/lens/index.tsx @@ -5,8 +5,7 @@ * 2.0. */ +export { LensChart, type LensChartProps } from './lens_chart'; export { ChartPlaceholder } from './chart_placeholder'; -export { LensWrapper } from './lens_wrapper'; - export { TooltipContent } from './metric_explanation/tooltip_content'; export { HostMetricsDocsLink } from './metric_explanation/host_metrics_docs_link'; diff --git a/x-pack/plugins/infra/public/components/lens/lens_chart.tsx b/x-pack/plugins/infra/public/components/lens/lens_chart.tsx new file mode 100644 index 0000000000000..2d4b599d56de2 --- /dev/null +++ b/x-pack/plugins/infra/public/components/lens/lens_chart.tsx @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { CSSProperties, useMemo } from 'react'; +import { EuiPanel, EuiToolTip, type EuiPanelProps } from '@elastic/eui'; +import { Action } from '@kbn/ui-actions-plugin/public'; +import { css } from '@emotion/react'; +import { useLensAttributes, type UseLensAttributesParams } from '../../hooks/use_lens_attributes'; +import type { BaseChartProps } from './types'; +import type { TooltipContentProps } from './metric_explanation/tooltip_content'; +import { LensWrapper } from './lens_wrapper'; +import { ChartLoadError } from './chart_load_error'; + +const MIN_HEIGHT = 300; + +export type LensChartProps = UseLensAttributesParams & + BaseChartProps & + Pick & { + toolTip?: React.ReactElement; + }; + +export const LensChart = ({ + id, + borderRadius, + dateRange, + filters, + hidePanelTitles, + lastReloadRequestTime, + query, + onBrushEnd, + overrides, + toolTip, + disableTriggers = false, + height = MIN_HEIGHT, + loading = false, + ...lensAttributesParams +}: LensChartProps) => { + const { formula, attributes, getExtraActions, error } = useLensAttributes({ + ...lensAttributesParams, + }); + + const isLoading = loading || !attributes; + + const extraActions: Action[] = useMemo( + () => + getExtraActions({ + timeRange: dateRange, + query, + filters, + }), + [dateRange, filters, getExtraActions, query] + ); + + const sytle: CSSProperties = useMemo(() => ({ height }), [height]); + + const Lens = ( + + ); + + const getContent = () => { + if (!toolTip) { + return Lens; + } + + return ( + + {Lens} + + ); + }; + + return ( + + {error ? : getContent()} + + ); +}; diff --git a/x-pack/plugins/infra/public/components/lens/lens_wrapper.tsx b/x-pack/plugins/infra/public/components/lens/lens_wrapper.tsx index dc3c11dccacc0..f203c9c344797 100644 --- a/x-pack/plugins/infra/public/components/lens/lens_wrapper.tsx +++ b/x-pack/plugins/infra/public/components/lens/lens_wrapper.tsx @@ -9,7 +9,8 @@ import type { Action } from '@kbn/ui-actions-plugin/public'; import { ViewMode } from '@kbn/embeddable-plugin/public'; import type { TimeRange } from '@kbn/es-query'; import { TypedLensByValueInput } from '@kbn/lens-plugin/public'; -import { euiStyled } from '@kbn/kibana-react-plugin/common'; +import { css } from '@emotion/react'; +import { useEuiTheme } from '@elastic/eui'; import { useKibanaContextForPlugin } from '../../hooks/use_kibana'; import { ChartLoadingProgress, ChartPlaceholder } from './chart_placeholder'; import { parseDateRange } from '../../utils/datemath'; @@ -30,10 +31,11 @@ export const LensWrapper = ({ dateRange, filters, lastReloadRequestTime, - loading, + loading = false, query, ...props }: LensWrapperProps) => { + const { euiTheme } = useEuiTheme(); const [intersectionObserverEntry, setIntersectionObserverEntry] = useState(); const [embeddableLoaded, setEmbeddableLoaded] = useState(false); @@ -96,11 +98,25 @@ export const LensWrapper = ({ return { from, to }; }, [state.dateRange]); - const isLoading = loading || !state.attributes; return ( - +
    <> {isLoading && !embeddableLoaded ? ( @@ -120,7 +136,7 @@ export const LensWrapper = ({ )} - +
    ); }; @@ -142,13 +158,3 @@ const EmbeddableComponentMemo = React.memo( return ; } ); - -const Container = euiStyled.div` - position: relative; - border-radius: ${({ theme }) => theme.eui.euiSizeS}; - overflow: hidden; - height: 100%; - .echLegend .echLegendList { - display: flex; - } -`; diff --git a/x-pack/plugins/infra/public/components/lens/metric_explanation/tooltip_content.tsx b/x-pack/plugins/infra/public/components/lens/metric_explanation/tooltip_content.tsx index fd46700130ee4..52459e70e2b05 100644 --- a/x-pack/plugins/infra/public/components/lens/metric_explanation/tooltip_content.tsx +++ b/x-pack/plugins/infra/public/components/lens/metric_explanation/tooltip_content.tsx @@ -11,14 +11,14 @@ import { css } from '@emotion/react'; import { FormattedMessage } from '@kbn/i18n-react'; import { HOST_METRICS_DOC_HREF } from '../../../common/visualizations/constants'; -interface Props extends Pick, 'style'> { +export interface TooltipContentProps extends Pick, 'style'> { description: string; formula?: string; showDocumentationLink?: boolean; } export const TooltipContent = React.memo( - ({ description, formula, showDocumentationLink = false, style }: Props) => { + ({ description, formula, showDocumentationLink = false, style }: TooltipContentProps) => { const onClick = (e: React.MouseEvent) => { e.stopPropagation(); }; diff --git a/x-pack/plugins/infra/public/components/lens/types.ts b/x-pack/plugins/infra/public/components/lens/types.ts new file mode 100644 index 0000000000000..8a4791de8cdf5 --- /dev/null +++ b/x-pack/plugins/infra/public/components/lens/types.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 type { DataView } from '@kbn/data-views-plugin/public'; +import type { LensWrapperProps } from './lens_wrapper'; + +export type BaseChartProps = Pick< + LensWrapperProps, + | 'id' + | 'dateRange' + | 'disableTriggers' + | 'filters' + | 'hidePanelTitles' + | 'lastReloadRequestTime' + | 'loading' + | 'overrides' + | 'onBrushEnd' + | 'query' + | 'title' +> & { + dataView?: DataView; + height?: number; +}; diff --git a/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts b/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts index 721bf5669d203..6f3ae0cf37aff 100644 --- a/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts +++ b/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts @@ -68,7 +68,9 @@ interface UseLensAttributesMetricChartParams visualizationType: 'lnsMetric'; } -type UseLensAttributesParams = UseLensAttributesXYChartParams | UseLensAttributesMetricChartParams; +export type UseLensAttributesParams = + | UseLensAttributesXYChartParams + | UseLensAttributesMetricChartParams; export const useLensAttributes = ({ dataView, diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/chart/metric_chart_wrapper.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/chart/metric_chart_wrapper.tsx index 97be988142aa0..e78aae020b46b 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/chart/metric_chart_wrapper.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/chart/metric_chart_wrapper.tsx @@ -6,8 +6,8 @@ */ import React, { useEffect, useRef, CSSProperties } from 'react'; import { Chart, Metric, type MetricWNumber, type MetricWTrend } from '@elastic/charts'; -import { EuiPanel, EuiToolTip } from '@elastic/eui'; -import styled from 'styled-components'; +import { EuiPanel, EuiToolTip, useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/react'; import { ChartPlaceholder } from '../../../../../components/lens'; export interface Props extends Pick { @@ -16,11 +16,11 @@ export interface Props extends Pick { + const euiTheme = useEuiTheme(); const loadedOnce = useRef(false); useEffect(() => { @@ -42,7 +42,7 @@ export const MetricChartWrapper = React.memo( }; return ( - + {loading && !loadedOnce.current ? ( ) : ( @@ -52,19 +52,20 @@ export const MetricChartWrapper = React.memo( content={toolTip} anchorClassName="eui-fullWidth" > - + - + )} ); } ); - -const KPIChartStyled = styled(Chart)` - .echMetric { - border-radius: ${(p) => p.theme.eui.euiBorderRadius}; - pointer-events: none; - } -`; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/hosts_tile.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/hosts_tile.tsx index 0571733b80034..f38e6772a3c84 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/hosts_tile.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/hosts_tile.tsx @@ -6,7 +6,6 @@ */ import { i18n } from '@kbn/i18n'; import React from 'react'; -import { KPIChartProps } from '../../../../../common/visualizations/lens/dashboards/host/kpi_grid_config'; import { hostLensFormulas } from '../../../../../common/visualizations'; import { useHostCountContext } from '../../hooks/use_host_count'; import { useUnifiedSearchContext } from '../../hooks/use_unified_search'; @@ -16,21 +15,20 @@ import { type Props, MetricChartWrapper } from '../chart/metric_chart_wrapper'; import { TooltipContent } from '../../../../../components/lens'; const HOSTS_CHART: Omit = { - id: `metric-hostCount`, + id: 'hostsViewKPI-hostsCount', color: '#6DCCB1', - title: i18n.translate('xpack.infra.hostsViewPage.metricTrend.hostCount.title', { + title: i18n.translate('xpack.infra.hostsViewPage.kpi.hostCount.title', { defaultMessage: 'Hosts', }), - ['data-test-subj']: 'hostsViewKPI-hostsCount', }; -export const HostsTile = ({ style }: Pick) => { +export const HostsTile = ({ height }: { height: number }) => { const { data: hostCountData, isRequestRunning: hostCountLoading } = useHostCountContext(); const { searchCriteria } = useUnifiedSearchContext(); const getSubtitle = () => { return searchCriteria.limit < (hostCountData?.count.value ?? 0) - ? i18n.translate('xpack.infra.hostsViewPage.metricTrend.subtitle.hostCount.limit', { + ? i18n.translate('xpack.infra.hostsViewPage.kpi.subtitle.hostCount.limit', { defaultMessage: 'Limited to {limit}', values: { limit: searchCriteria.limit, @@ -42,7 +40,7 @@ export const HostsTile = ({ style }: Pick) => { return ( { return ( @@ -26,11 +24,11 @@ export const KPIGrid = () => { - + {KPI_CHARTS.map((chartProp, index) => ( - + ))} diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/tile.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/tile.tsx index 950e74478dd4b..7211c89ce9071 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/tile.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/tile.tsx @@ -4,53 +4,47 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useMemo, useCallback } from 'react'; - +import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; -import { BrushTriggerEvent } from '@kbn/charts-plugin/public'; -import { EuiIcon, EuiPanel, EuiFlexGroup, EuiFlexItem, EuiText, EuiToolTip } from '@elastic/eui'; -import styled from 'styled-components'; -import { Action } from '@kbn/ui-actions-plugin/public'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { LensWrapper, TooltipContent } from '../../../../../components/lens'; -import { KPIChartProps } from '../../../../../common/visualizations/lens/dashboards/host/kpi_grid_config'; +import { LensChart, TooltipContent } from '../../../../../components/lens'; +import { + type KPIChartProps, + AVERAGE_SUBTITLE, +} from '../../../../../common/visualizations/lens/dashboards/host/kpi_grid_config'; import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; -import { useLensAttributes } from '../../../../../hooks/use_lens_attributes'; import { useMetricsDataViewContext } from '../../hooks/use_data_view'; import { useUnifiedSearchContext } from '../../hooks/use_unified_search'; import { useHostsViewContext } from '../../hooks/use_hosts_view'; import { useHostCountContext } from '../../hooks/use_host_count'; import { useAfterLoadedState } from '../../hooks/use_after_loaded_state'; -import { KPI_CHART_MIN_HEIGHT } from '../../constants'; -export const Tile = ({ id, title, layers, style, toolTip }: KPIChartProps) => { - const { searchCriteria, onSubmit } = useUnifiedSearchContext(); +export const Tile = ({ + id, + title, + layers, + toolTip, + height, +}: KPIChartProps & { height: number }) => { + const { searchCriteria } = useUnifiedSearchContext(); const { dataView } = useMetricsDataViewContext(); const { requestTs, hostNodes, loading: hostsLoading } = useHostsViewContext(); const { data: hostCountData, isRequestRunning: hostCountLoading } = useHostCountContext(); const shouldUseSearchCriteria = hostNodes.length === 0; + const loading = hostsLoading || hostCountLoading; + const getSubtitle = () => { return searchCriteria.limit < (hostCountData?.count.value ?? 0) - ? i18n.translate('xpack.infra.hostsViewPage.metricTrend.subtitle.average.limit', { + ? i18n.translate('xpack.infra.hostsViewPage.kpi.subtitle.average.limit', { defaultMessage: 'Average (of {limit} hosts)', values: { limit: searchCriteria.limit, }, }) - : i18n.translate('xpack.infra.hostsViewPage.metricTrend.subtitle.average', { - defaultMessage: 'Average', - }); + : AVERAGE_SUBTITLE; }; - const { formula, attributes, getExtraActions, error } = useLensAttributes({ - dataView, - title, - layers: { ...layers, options: { ...layers.options, subtitle: getSubtitle() } }, - visualizationType: 'lnsMetric', - }); - const filters = useMemo(() => { return shouldUseSearchCriteria ? searchCriteria.filters @@ -61,106 +55,33 @@ export const Tile = ({ id, title, layers, style, toolTip }: KPIChartProps) => { dataView, }), ]; - }, [shouldUseSearchCriteria, searchCriteria.filters, hostNodes, dataView]); - - const loading = hostsLoading || !attributes || hostCountLoading; + }, [dataView, hostNodes, searchCriteria.filters, shouldUseSearchCriteria]); - // prevents requestTs and serchCriteria states from reloading the chart - // we want it to reload only once the host count and table have finished loading + // prevents requestTs and searchCriteria state from reloading the chart + // we want it to reload only once the table has finished loading const { afterLoadedState } = useAfterLoadedState(loading, { - attributes, lastReloadRequestTime: requestTs, - ...searchCriteria, + dateRange: searchCriteria.dateRange, + query: shouldUseSearchCriteria ? searchCriteria.query : undefined, filters, }); - const extraActions: Action[] = useMemo( - () => - getExtraActions({ - timeRange: afterLoadedState.dateRange, - query: shouldUseSearchCriteria ? afterLoadedState.query : undefined, - filters, - }), - [ - afterLoadedState.dateRange, - afterLoadedState.query, - filters, - getExtraActions, - shouldUseSearchCriteria, - ] - ); - - const handleBrushEnd = useCallback( - ({ range }: BrushTriggerEvent['data']) => { - const [min, max] = range; - onSubmit({ - dateRange: { - from: new Date(min).toISOString(), - to: new Date(max).toISOString(), - mode: 'absolute', - }, - }); - }, - [onSubmit] - ); - return ( - - {error ? ( - - - - - - - - - - - ) : ( - } - anchorClassName="eui-fullWidth" - > -
    - -
    -
    - )} -
    + } + visualizationType="lnsMetric" + disableTriggers + hidePanelTitles + /> ); }; - -const EuiPanelStyled = styled(EuiPanel)` - min-height: ${KPI_CHART_MIN_HEIGHT}px; - .echMetric { - border-radius: ${({ theme }) => theme.eui.euiBorderRadius}; - pointer-events: none; - } -`; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/metric_chart.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/metric_chart.tsx index b31e5c1cb08d2..c0f05c55d1e9e 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/metric_chart.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/metric_chart.tsx @@ -4,59 +4,35 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { CSSProperties, useCallback, useMemo } from 'react'; -import { Action } from '@kbn/ui-actions-plugin/public'; -import { BrushTriggerEvent } from '@kbn/charts-plugin/public'; -import { EuiIcon, EuiPanel, EuiFlexGroup, EuiFlexItem, EuiText, useEuiTheme } from '@elastic/eui'; -import { css } from '@emotion/react'; -import { TypedLensByValueInput } from '@kbn/lens-plugin/public'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { LensWrapper } from '../../../../../../components/lens'; -import { useLensAttributes, Layer } from '../../../../../../hooks/use_lens_attributes'; +import React, { useMemo } from 'react'; +import type { TypedLensByValueInput } from '@kbn/lens-plugin/public'; +import { LensChart } from '../../../../../../components/lens'; +import type { Layer } from '../../../../../../hooks/use_lens_attributes'; import { useMetricsDataViewContext } from '../../../hooks/use_data_view'; import { useUnifiedSearchContext } from '../../../hooks/use_unified_search'; -import { FormulaConfig, XYLayerOptions } from '../../../../../../common/visualizations'; +import type { FormulaConfig, XYLayerOptions } from '../../../../../../common/visualizations'; import { useHostsViewContext } from '../../../hooks/use_hosts_view'; import { buildCombinedHostsFilter } from '../../../../../../utils/filters/build'; import { useHostsTableContext } from '../../../hooks/use_hosts_table'; import { useAfterLoadedState } from '../../../hooks/use_after_loaded_state'; -import { METRIC_CHART_MIN_HEIGHT } from '../../../constants'; +import { METRIC_CHART_HEIGHT } from '../../../constants'; export interface MetricChartProps extends Pick { title: string; layers: Array>; } -const lensStyle: CSSProperties = { - height: METRIC_CHART_MIN_HEIGHT, -}; - export const MetricChart = ({ id, title, layers, overrides }: MetricChartProps) => { - const { euiTheme } = useEuiTheme(); - const { searchCriteria, onSubmit } = useUnifiedSearchContext(); + const { searchCriteria } = useUnifiedSearchContext(); const { dataView } = useMetricsDataViewContext(); const { requestTs, loading } = useHostsViewContext(); const { currentPage } = useHostsTableContext(); const shouldUseSearchCriteria = currentPage.length === 0; - // prevents requestTs and serchCriteria states from reloading the chart - // we want it to reload only once the table has finished loading - const { afterLoadedState } = useAfterLoadedState(loading, { - lastReloadRequestTime: requestTs, - ...searchCriteria, - }); - - const { attributes, getExtraActions, error } = useLensAttributes({ - dataView, - layers, - title, - visualizationType: 'lnsXY', - }); - const filters = useMemo(() => { return shouldUseSearchCriteria - ? afterLoadedState.filters + ? searchCriteria.filters : [ buildCombinedHostsFilter({ field: 'host.name', @@ -64,85 +40,31 @@ export const MetricChart = ({ id, title, layers, overrides }: MetricChartProps) dataView, }), ]; - }, [afterLoadedState.filters, currentPage, dataView, shouldUseSearchCriteria]); - - const extraActions: Action[] = useMemo( - () => - getExtraActions({ - timeRange: afterLoadedState.dateRange, - query: shouldUseSearchCriteria ? afterLoadedState.query : undefined, - filters, - }), - [ - afterLoadedState.dateRange, - afterLoadedState.query, - filters, - getExtraActions, - shouldUseSearchCriteria, - ] - ); + }, [searchCriteria.filters, currentPage, dataView, shouldUseSearchCriteria]); - const handleBrushEnd = useCallback( - ({ range }: BrushTriggerEvent['data']) => { - const [min, max] = range; - onSubmit({ - dateRange: { - from: new Date(min).toISOString(), - to: new Date(max).toISOString(), - mode: 'absolute', - }, - }); - }, - [onSubmit] - ); + // prevents requestTs and searchCriteria state from reloading the chart + // we want it to reload only once the table has finished loading + const { afterLoadedState } = useAfterLoadedState(loading, { + lastReloadRequestTime: requestTs, + dateRange: searchCriteria.dateRange, + query: shouldUseSearchCriteria ? searchCriteria.query : undefined, + }); return ( - - {error ? ( - - - - - - - - - - - ) : ( - - )} - + dataView={dataView} + dateRange={afterLoadedState.dateRange} + height={METRIC_CHART_HEIGHT} + layers={layers} + lastReloadRequestTime={afterLoadedState.lastReloadRequestTime} + loading={loading} + filters={filters} + query={afterLoadedState.query} + title={title} + overrides={overrides} + visualizationType="lnsXY" + /> ); }; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/constants.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/constants.ts index 296d779e8a0fd..aace07448692e 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/constants.ts +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/constants.ts @@ -15,8 +15,7 @@ export const DEFAULT_PAGE_SIZE = 10; export const LOCAL_STORAGE_HOST_LIMIT_KEY = 'hostsView:hostLimitSelection'; export const LOCAL_STORAGE_PAGE_SIZE_KEY = 'hostsView:pageSizeSelection'; -export const KPI_CHART_MIN_HEIGHT = 150; -export const METRIC_CHART_MIN_HEIGHT = 300; +export const METRIC_CHART_HEIGHT = 300; export const HOST_LIMIT_OPTIONS = [50, 100, 500] as const; export const HOST_METRICS_DOC_HREF = 'https://ela.st/docs-infra-host-metrics'; diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index fafb56aed9727..11f22770bec5f 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -18661,8 +18661,8 @@ "xpack.infra.homePage.toolbar.showingLastOneMinuteDataText": "Dernières {duration} de données pour l'heure sélectionnée", "xpack.infra.hostsViewPage.errorOnCreateOrLoadDataview": "Une erreur s’est produite lors de la création d’une vue de données : {metricAlias}. Essayez de recharger la page.", "xpack.infra.hostsViewPage.landing.calloutRoleClarificationWithDocsLink": "Un rôle avec accès aux paramètres avancés dans Kibana sera nécessaire. {docsLink}", - "xpack.infra.hostsViewPage.metricTrend.subtitle.average.limit": "Moyenne (de {limit} hôtes)", - "xpack.infra.hostsViewPage.metricTrend.subtitle.hostCount.limit": "Limité à {limit}", + "xpack.infra.hostsViewPage.kpi.subtitle.average.limit": "Moyenne (de {limit} hôtes)", + "xpack.infra.hostsViewPage.kpi.subtitle.hostCount.limit": "Limité à {limit}", "xpack.infra.hostsViewPage.table.selectedHostsButton": "Sélection effectuée de {selectedHostsCount} {selectedHostsCount, plural, =1 {hôte} one {hôtes} many {hôtes} other {hôtes}}", "xpack.infra.hostsViewPage.table.tooltip.documentationLabel": "Pour en savoir plus, consultez {documentation}", "xpack.infra.inventoryTimeline.header": "Moyenne {metricLabel}", @@ -18801,6 +18801,11 @@ "xpack.infra.assetDetailsEmbeddable.description": "Ajoutez une vue de détails de ressource.", "xpack.infra.assetDetailsEmbeddable.displayName": "Détails de ressource", "xpack.infra.assetDetailsEmbeddable.title": "Détails de ressource", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.cpuUsage.title": "Utilisation CPU", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.diskSpaceUsage.title": "Utilisation de l’espace disque", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.memoryUsage.title": "Utilisation mémoire", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.normalizedLoad1m.title": "Charge normalisée", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.subtitle.average": "Moyenne", "xpack.infra.bottomDrawer.kubernetesDashboardsLink": "Tableaux de bord Kubernetes", "xpack.infra.chartSection.missingMetricDataBody": "Les données de ce graphique sont manquantes.", "xpack.infra.chartSection.missingMetricDataText": "Données manquantes", @@ -18885,6 +18890,7 @@ "xpack.infra.hostsViewPage.errorOnCreateOrLoadDataviewTitle": "Erreur lors de la création d'un Data View", "xpack.infra.hostsViewPage.hostLimit": "Limite de l'hôte", "xpack.infra.hostsViewPage.hostLimit.tooltip": "Pour garantir des performances de recherche plus rapides, le nombre d'hôtes retournés est limité.", + "xpack.infra.hostsViewPage.kpi.hostCount.title": "Hôtes", "xpack.infra.hostsViewPage.landing.calloutReachOutToYourKibanaAdministrator": "Votre rôle d'utilisateur ne dispose pas des privilèges suffisants pour activer cette fonctionnalité - veuillez \n contacter votre administrateur Kibana et lui demander de visiter cette page pour activer la fonctionnalité.", "xpack.infra.hostsViewPage.landing.enableHostsView": "Activer la vue des hôtes", "xpack.infra.hostsViewPage.landing.introMessage": "Bienvenue sur la fonctionnalité \"Hôtes\", désormais disponible en version bêta. Avec ce puissant outil, \n vous pouvez facilement voir et analyser vos hôtes et identifier tout problème afin de les corriger rapidement. \n Obtenez une vue détaillée des indicateurs pour vos hôtes afin de savoir lesquels déclenchent le plus d’alertes, et filtrez \n les hôtes que vous voulez analyser à l'aide de tout filtre KQL ainsi que de répartitions simples comme le fournisseur cloud et \n le système d'exploitation.", @@ -18901,12 +18907,6 @@ "xpack.infra.hostsViewPage.metrics.tooltip.normalizedLoad1m": "Moyenne de la charge sur 1 minute normalisée par le nombre de cœurs de processeur. ", "xpack.infra.hostsViewPage.metrics.tooltip.rx": "Nombre d'octets qui ont été reçus par seconde sur les interfaces publiques des hôtes.", "xpack.infra.hostsViewPage.metrics.tooltip.tx": "Nombre d'octets envoyés par seconde sur les interfaces publiques des hôtes.", - "xpack.infra.hostsViewPage.metricTrend.cpuUsage.title": "Utilisation CPU", - "xpack.infra.hostsViewPage.metricTrend.diskSpaceUsage.title": "Utilisation de l’espace disque", - "xpack.infra.hostsViewPage.metricTrend.hostCount.title": "Hôtes", - "xpack.infra.hostsViewPage.metricTrend.memoryUsage.title": "Utilisation mémoire", - "xpack.infra.hostsViewPage.metricTrend.normalizedLoad1m.title": "Charge normalisée", - "xpack.infra.hostsViewPage.metricTrend.subtitle.average": "Moyenne", "xpack.infra.hostsViewPage.table.addFilter": "Ajouter un filtre", "xpack.infra.hostsViewPage.table.cpuUsageColumnHeader": "Utilisation CPU (moy.)", "xpack.infra.hostsViewPage.table.diskSpaceUsageColumnHeader": "Utilisation de l’espace disque (moy.)", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 66ea13be17908..15960dbd920ed 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -18675,8 +18675,8 @@ "xpack.infra.homePage.toolbar.showingLastOneMinuteDataText": "指定期間のデータの最後の{duration}", "xpack.infra.hostsViewPage.errorOnCreateOrLoadDataview": "データビューの作成中にエラーが発生しました:{metricAlias}。ページを再読み込みしてください。", "xpack.infra.hostsViewPage.landing.calloutRoleClarificationWithDocsLink": "Kibanaの高度な設定にアクセスできるロールが必要です。{docsLink}", - "xpack.infra.hostsViewPage.metricTrend.subtitle.average.limit": "({limit}ホストの)平均", - "xpack.infra.hostsViewPage.metricTrend.subtitle.hostCount.limit": "{limit}に制限", + "xpack.infra.hostsViewPage.kpi.subtitle.average.limit": "({limit}ホストの)平均", + "xpack.infra.hostsViewPage.kpi.subtitle.hostCount.limit": "{limit}に制限", "xpack.infra.hostsViewPage.table.selectedHostsButton": "{selectedHostsCount}件の{selectedHostsCount, plural, =1 {ホスト} other {ホスト}}が選択済み", "xpack.infra.hostsViewPage.table.tooltip.documentationLabel": "詳細については、{documentation}を参照してください。", "xpack.infra.inventoryTimeline.header": "平均{metricLabel}", @@ -18815,6 +18815,11 @@ "xpack.infra.assetDetailsEmbeddable.description": "アセット詳細ビューを追加します。", "xpack.infra.assetDetailsEmbeddable.displayName": "アセット詳細", "xpack.infra.assetDetailsEmbeddable.title": "アセット詳細", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.cpuUsage.title": "CPU使用状況", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.diskSpaceUsage.title": "ディスク容量使用状況", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.memoryUsage.title": "メモリー使用状況", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.normalizedLoad1m.title": "正規化された負荷", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.subtitle.average": "平均", "xpack.infra.bottomDrawer.kubernetesDashboardsLink": "Kubernetesダッシュボード", "xpack.infra.chartSection.missingMetricDataBody": "このチャートはデータが欠けています。", "xpack.infra.chartSection.missingMetricDataText": "データが欠けています", @@ -18899,6 +18904,7 @@ "xpack.infra.hostsViewPage.errorOnCreateOrLoadDataviewTitle": "データビューの作成エラー", "xpack.infra.hostsViewPage.hostLimit": "ホスト制限", "xpack.infra.hostsViewPage.hostLimit.tooltip": "クエリパフォーマンスを確実に高めるために、返されるホスト数には制限があります", + "xpack.infra.hostsViewPage.kpi.hostCount.title": "ホスト", "xpack.infra.hostsViewPage.landing.calloutReachOutToYourKibanaAdministrator": "ユーザーロールには、この機能を有効にするための十分な権限がありません。 \n この機能を有効にするために、Kibana管理者に連絡して、このページにアクセスするように依頼してください。", "xpack.infra.hostsViewPage.landing.enableHostsView": "ホストビューを有効化", "xpack.infra.hostsViewPage.landing.introMessage": "「ホスト」機能へようこそ!ベータ版でご利用いただけるようになりました。この強力なツールを使用すると、\n ホストを簡単に表示、分析し、あらゆる問題を特定して、迅速に対処できます。\n ホストのメトリックを詳細に表示し、どのメトリックが最も多くのアラートをトリガーしているかを確認し、 \n 任意のKQLフィルターを使用して分析したいホストや、クラウドプロバイダーやオペレーティングシステムといった簡単な内訳をフィルターできます \n 。", @@ -18915,12 +18921,6 @@ "xpack.infra.hostsViewPage.metrics.tooltip.normalizedLoad1m": "CPUコア数で正規化した1分間の負荷平均。", "xpack.infra.hostsViewPage.metrics.tooltip.rx": "ホストのパブリックインターフェースで1秒間に受信したバイト数。", "xpack.infra.hostsViewPage.metrics.tooltip.tx": "ホストのパブリックインターフェースで1秒間に送信したバイト数。", - "xpack.infra.hostsViewPage.metricTrend.cpuUsage.title": "CPU使用状況", - "xpack.infra.hostsViewPage.metricTrend.diskSpaceUsage.title": "ディスク容量使用状況", - "xpack.infra.hostsViewPage.metricTrend.hostCount.title": "ホスト", - "xpack.infra.hostsViewPage.metricTrend.memoryUsage.title": "メモリー使用状況", - "xpack.infra.hostsViewPage.metricTrend.normalizedLoad1m.title": "正規化された負荷", - "xpack.infra.hostsViewPage.metricTrend.subtitle.average": "平均", "xpack.infra.hostsViewPage.table.addFilter": "フィルターを追加します", "xpack.infra.hostsViewPage.table.cpuUsageColumnHeader": "CPU使用状況(平均)", "xpack.infra.hostsViewPage.table.diskSpaceUsageColumnHeader": "ディスク容量使用状況(平均)", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 7b86064bc4322..0cff43087c67f 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -18675,8 +18675,8 @@ "xpack.infra.homePage.toolbar.showingLastOneMinuteDataText": "选定时间过去 {duration}的数据", "xpack.infra.hostsViewPage.errorOnCreateOrLoadDataview": "尝试创建以下数据视图时出错:{metricAlias}。尝试重新加载该页面。", "xpack.infra.hostsViewPage.landing.calloutRoleClarificationWithDocsLink": "他们将需要有权访问 Kibana 中的高级设置的角色。{docsLink}", - "xpack.infra.hostsViewPage.metricTrend.subtitle.average.limit": "平均值(属于 {limit} 台主机)", - "xpack.infra.hostsViewPage.metricTrend.subtitle.hostCount.limit": "限定为 {limit}", + "xpack.infra.hostsViewPage.kpi.subtitle.average.limit": "平均值(属于 {limit} 台主机)", + "xpack.infra.hostsViewPage.kpi.subtitle.hostCount.limit": "限定为 {limit}", "xpack.infra.hostsViewPage.table.selectedHostsButton": "已选定 {selectedHostsCount} 个{selectedHostsCount, plural, =1 {主机} other {主机}}", "xpack.infra.hostsViewPage.table.tooltip.documentationLabel": "请参阅 {documentation} 了解更多信息", "xpack.infra.inventoryTimeline.header": "平均值 {metricLabel}", @@ -18815,6 +18815,11 @@ "xpack.infra.assetDetailsEmbeddable.description": "添加资产详情视图。", "xpack.infra.assetDetailsEmbeddable.displayName": "资产详情", "xpack.infra.assetDetailsEmbeddable.title": "资产详情", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.cpuUsage.title": "CPU 使用率", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.diskSpaceUsage.title": "磁盘空间使用率", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.memoryUsage.title": "内存利用率", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.normalizedLoad1m.title": "标准化负载", + "xpack.infra.assetDetailsEmbeddable.overview.kpi.subtitle.average": "平均值", "xpack.infra.bottomDrawer.kubernetesDashboardsLink": "Kubernetes 仪表板", "xpack.infra.chartSection.missingMetricDataBody": "此图表的数据缺失。", "xpack.infra.chartSection.missingMetricDataText": "缺失数据", @@ -18899,6 +18904,7 @@ "xpack.infra.hostsViewPage.errorOnCreateOrLoadDataviewTitle": "创建数据视图时出错", "xpack.infra.hostsViewPage.hostLimit": "主机限制", "xpack.infra.hostsViewPage.hostLimit.tooltip": "为确保更快的查询性能,对返回的主机数量实施了限制", + "xpack.infra.hostsViewPage.kpi.hostCount.title": "主机", "xpack.infra.hostsViewPage.landing.calloutReachOutToYourKibanaAdministrator": "您的用户角色权限不足,无法启用此功能 - 请 \n 联系您的 Kibana 管理员,要求他们访问此页面以启用该功能。", "xpack.infra.hostsViewPage.landing.enableHostsView": "启用主机视图", "xpack.infra.hostsViewPage.landing.introMessage": "欢迎使用“主机”功能,该功能现在为公测版!使用这个强大的工具,\n 您可以轻松查看并分析主机,并确定任何问题以便快速予以解决。\n 获取您主机的详细指标视图,了解哪些指标触发了大多数告警, \n 并使用任何 KQL 筛选以及云提供商和操作系统等常见细目筛选 \n 您要分析的主机。", @@ -18915,12 +18921,6 @@ "xpack.infra.hostsViewPage.metrics.tooltip.normalizedLoad1m": "1 分钟负载平均值,按 CPU 核心数进行标准化。", "xpack.infra.hostsViewPage.metrics.tooltip.rx": "主机的公共接口上每秒接收的字节数。", "xpack.infra.hostsViewPage.metrics.tooltip.tx": "主机的公共接口上每秒发送的字节数。", - "xpack.infra.hostsViewPage.metricTrend.cpuUsage.title": "CPU 使用率", - "xpack.infra.hostsViewPage.metricTrend.diskSpaceUsage.title": "磁盘空间使用率", - "xpack.infra.hostsViewPage.metricTrend.hostCount.title": "主机", - "xpack.infra.hostsViewPage.metricTrend.memoryUsage.title": "内存利用率", - "xpack.infra.hostsViewPage.metricTrend.normalizedLoad1m.title": "标准化负载", - "xpack.infra.hostsViewPage.metricTrend.subtitle.average": "平均值", "xpack.infra.hostsViewPage.table.addFilter": "添加筛选", "xpack.infra.hostsViewPage.table.cpuUsageColumnHeader": "CPU 使用率(平均值)", "xpack.infra.hostsViewPage.table.diskSpaceUsageColumnHeader": "磁盘空间使用率(平均值)", diff --git a/x-pack/test/functional/page_objects/infra_hosts_view.ts b/x-pack/test/functional/page_objects/infra_hosts_view.ts index b56b57843cd3b..00ae0af08cf07 100644 --- a/x-pack/test/functional/page_objects/infra_hosts_view.ts +++ b/x-pack/test/functional/page_objects/infra_hosts_view.ts @@ -206,7 +206,7 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) { // Flyout Tabs async getAssetDetailsKPITileValue(type: string) { const container = await testSubjects.find('assetDetailsKPIGrid'); - const element = await container.findByTestSubject(`assetDetailsKPI-${type}`); + const element = await container.findByTestSubject(`infraAssetDetailsKPI${type}`); const div = await element.findByClassName('echMetricText__value'); return div.getAttribute('title'); }, @@ -229,7 +229,7 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) { async getAssetDetailsMetricsCharts() { const container = await testSubjects.find('assetDetailsMetricsChartGrid'); - return container.findAllByCssSelector('[data-test-subj*="assetDetailsMetricsChart"]'); + return container.findAllByCssSelector('[data-test-subj*="infraAssetDetailsMetricsChart"]'); }, getMetadataTab() { From c0fe4ac2eb1b9a91b7f331173e38be1c8c1dbffb Mon Sep 17 00:00:00 2001 From: Paulo Henrique Date: Wed, 9 Aug 2023 08:19:02 -0700 Subject: [PATCH 10/22] [Cloud Security] [Findings] [Misconfigurations] [Alerts] - Create detection rule (#162750) Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../common/api/create_detection_rule.ts | 59 ++++++++ .../public/components/take_action.tsx | 129 ++++++++++++++++++ .../public/components/test_subjects.ts | 5 +- .../findings_flyout/findings_flyout.tsx | 11 +- .../create_detection_rule_from_finding.ts | 99 ++++++++++++++ .../cloud_security_posture/tsconfig.json | 2 +- 6 files changed, 302 insertions(+), 3 deletions(-) create mode 100644 x-pack/plugins/cloud_security_posture/public/common/api/create_detection_rule.ts create mode 100644 x-pack/plugins/cloud_security_posture/public/components/take_action.tsx create mode 100644 x-pack/plugins/cloud_security_posture/public/pages/configurations/utils/create_detection_rule_from_finding.ts diff --git a/x-pack/plugins/cloud_security_posture/public/common/api/create_detection_rule.ts b/x-pack/plugins/cloud_security_posture/public/common/api/create_detection_rule.ts new file mode 100644 index 0000000000000..ef0aa3321f35e --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/common/api/create_detection_rule.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { HttpSetup } from '@kbn/core/public'; + +const DETECTION_ENGINE_URL = '/api/detection_engine' as const; +const DETECTION_ENGINE_RULES_URL = `${DETECTION_ENGINE_URL}/rules` as const; + +interface RuleCreateProps { + type: string; + language: string; + license: string; + author: string[]; + filters: any[]; + false_positives: any[]; + risk_score: number; + risk_score_mapping: any[]; + severity: string; + severity_mapping: any[]; + threat: any[]; + interval: string; + from: string; + to: string; + timestamp_override: string; + timestamp_override_fallback_disabled: boolean; + actions: any[]; + enabled: boolean; + alert_suppression: { + group_by: string[]; + missing_fields_strategy: string; + }; + index: string[]; + query: string; + references: string[]; + name: string; + description: string; + tags: string[]; +} + +export interface RuleResponse extends RuleCreateProps { + id: string; +} + +export const createDetectionRule = async ({ + http, + rule, +}: { + http: HttpSetup; + rule: RuleCreateProps; +}): Promise => { + const res = await http.post(DETECTION_ENGINE_RULES_URL, { + body: JSON.stringify(rule), + }); + + return res as RuleResponse; +}; diff --git a/x-pack/plugins/cloud_security_posture/public/components/take_action.tsx b/x-pack/plugins/cloud_security_posture/public/components/take_action.tsx new file mode 100644 index 0000000000000..57684d02fd157 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/take_action.tsx @@ -0,0 +1,129 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState } from 'react'; +import { + EuiButton, + EuiContextMenuItem, + EuiContextMenuPanel, + EuiFlexGroup, + EuiFlexItem, + EuiPopover, + EuiText, + useGeneratedHtmlId, +} from '@elastic/eui'; +import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import type { HttpSetup } from '@kbn/core/public'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { CREATE_RULE_ACTION_SUBJ, TAKE_ACTION_SUBJ } from './test_subjects'; +import { useKibana } from '../common/hooks/use_kibana'; +import type { RuleResponse } from '../common/api/create_detection_rule'; + +const RULE_PAGE_PATH = '/app/security/rules/id/'; + +interface TakeActionProps { + createRuleFn: (http: HttpSetup) => Promise; +} +/* + * This component is used to create a detection rule from Flyout. + * It accepts a createRuleFn parameter which is used to create a rule in a generic way. + */ +export const TakeAction = ({ createRuleFn }: TakeActionProps) => { + const [isPopoverOpen, setPopoverOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const closePopover = () => { + setPopoverOpen(false); + }; + + const smallContextMenuPopoverId = useGeneratedHtmlId({ + prefix: 'smallContextMenuPopover', + }); + + const { http, notifications } = useKibana().services; + + const showSuccessToast = (ruleResponse: RuleResponse) => { + return notifications.toasts.addSuccess({ + toastLifeTimeMs: 10000, + color: 'success', + iconType: '', + text: toMountPoint( +
    + + {ruleResponse.name} + {` `} + + + + + + + + + + + + +
    + ), + }); + }; + + const button = ( + setPopoverOpen(!isPopoverOpen)} + > + + + ); + + return ( + + { + closePopover(); + setIsLoading(true); + const ruleResponse = await createRuleFn(http); + setIsLoading(false); + showSuccessToast(ruleResponse); + }} + data-test-subj={CREATE_RULE_ACTION_SUBJ} + > + + , + ]} + /> + + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts b/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts index 638076818d3f0..a1fa5d985df3c 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts @@ -32,4 +32,7 @@ export const NO_VULNERABILITIES_STATUS_TEST_SUBJ = { export const VULNERABILITIES_CONTAINER_TEST_SUBJ = 'vulnerabilities_container'; -export const VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ = 'vuknerabilities_cvss_score_badge'; +export const VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ = 'vulnerabilities_cvss_score_badge'; + +export const TAKE_ACTION_SUBJ = 'csp:take_action'; +export const CREATE_RULE_ACTION_SUBJ = 'csp:create_rule'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx index f59463e00125f..2c59f360850d8 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx @@ -25,9 +25,11 @@ import { } from '@elastic/eui'; import { assertNever } from '@kbn/std'; import { i18n } from '@kbn/i18n'; +import type { HttpSetup } from '@kbn/core/public'; import cisLogoIcon from '../../../assets/icons/cis_logo.svg'; import { CspFinding } from '../../../../common/schemas/csp_finding'; import { CspEvaluationBadge } from '../../../components/csp_evaluation_badge'; +import { TakeAction } from '../../../components/take_action'; import { TableTab } from './table_tab'; import { JsonTab } from './json_tab'; import { OverviewTab } from './overview_tab'; @@ -36,6 +38,7 @@ import type { BenchmarkId } from '../../../../common/types'; import { CISBenchmarkIcon } from '../../../components/cis_benchmark_icon'; import { BenchmarkName } from '../../../../common/types'; import { FINDINGS_FLYOUT } from '../test_subjects'; +import { createDetectionRuleFromFinding } from '../utils/create_detection_rule_from_finding'; const tabs = [ { @@ -127,6 +130,9 @@ export const FindingsRuleFlyout = ({ }: FindingFlyoutProps) => { const [tab, setTab] = useState(tabs[0]); + const createMisconfigurationRuleFn = async (http: HttpSetup) => + await createDetectionRuleFromFinding(http, findings); + return ( @@ -160,7 +166,7 @@ export const FindingsRuleFlyout = ({ - + + + + diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/utils/create_detection_rule_from_finding.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/utils/create_detection_rule_from_finding.ts new file mode 100644 index 0000000000000..179ac6e27713c --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/utils/create_detection_rule_from_finding.ts @@ -0,0 +1,99 @@ +/* + * 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 { HttpSetup } from '@kbn/core/public'; +import type { CspFinding } from '../../../../common/schemas/csp_finding'; +import { LATEST_FINDINGS_INDEX_DEFAULT_NS } from '../../../../common/constants'; +import { createDetectionRule } from '../../../common/api/create_detection_rule'; + +const DEFAULT_RULE_RISK_SCORE = 0; +const DEFAULT_RULE_SEVERITY = 'low'; +const DEFAULT_RULE_ENABLED = true; +const DEFAULT_RULE_AUTHOR = 'Elastic'; +const DEFAULT_RULE_LICENSE = 'Elastic License v2'; +const ALERT_SUPPRESSION_FIELD = 'resource.id'; +const ALERT_TIMESTAMP_FIELD = 'event.ingested'; + +enum AlertSuppressionMissingFieldsStrategy { + // per each document a separate alert will be created + DoNotSuppress = 'doNotSuppress', + // only one alert will be created per suppress by bucket + Suppress = 'suppress', +} + +const convertReferencesLinksToArray = (input: string | undefined) => { + if (!input) { + return []; + } + // Match all URLs in the input string using a regular expression + const matches = input.match(/(https?:\/\/\S+)/g); + + if (!matches) { + return []; + } + + // Remove the numbers and new lines + return matches.map((link) => link.replace(/^\d+\. /, '').replace(/\n/g, '')); +}; + +const STATIC_RULE_TAGS = ['Elastic', 'Cloud Security']; + +const generateMisconfigurationsTags = (finding: CspFinding) => { + return [STATIC_RULE_TAGS] + .concat(finding.rule.tags) + .concat( + finding.rule.benchmark.posture_type ? [finding.rule.benchmark.posture_type.toUpperCase()] : [] + ) + .flat(); +}; + +const generateMisconfigurationsRuleQuery = (finding: CspFinding) => { + return ` + rule.benchmark.rule_number: "${finding.rule.benchmark.rule_number}" + AND rule.benchmark.id: "${finding.rule.benchmark.id}" + AND result.evaluation: "failed" + `; +}; + +/* + * Creates a detection rule from a CspFinding + */ +export const createDetectionRuleFromFinding = async (http: HttpSetup, finding: CspFinding) => { + return await createDetectionRule({ + http, + rule: { + type: 'query', + language: 'kuery', + license: DEFAULT_RULE_LICENSE, + author: [DEFAULT_RULE_AUTHOR], + filters: [], + false_positives: [], + risk_score: DEFAULT_RULE_RISK_SCORE, + risk_score_mapping: [], + severity: DEFAULT_RULE_SEVERITY, + severity_mapping: [], + threat: [], + interval: '1h', + from: 'now-7200s', + to: 'now', + timestamp_override: ALERT_TIMESTAMP_FIELD, + timestamp_override_fallback_disabled: false, + actions: [], + enabled: DEFAULT_RULE_ENABLED, + alert_suppression: { + group_by: [ALERT_SUPPRESSION_FIELD], + missing_fields_strategy: AlertSuppressionMissingFieldsStrategy.Suppress, + }, + index: [LATEST_FINDINGS_INDEX_DEFAULT_NS], + query: generateMisconfigurationsRuleQuery(finding), + references: convertReferencesLinksToArray(finding.rule.references), + name: finding.rule.name, + description: finding.rule.rationale, + tags: generateMisconfigurationsTags(finding), + }, + }); +}; diff --git a/x-pack/plugins/cloud_security_posture/tsconfig.json b/x-pack/plugins/cloud_security_posture/tsconfig.json index ae8f7d610002b..a88bbf2bd0995 100755 --- a/x-pack/plugins/cloud_security_posture/tsconfig.json +++ b/x-pack/plugins/cloud_security_posture/tsconfig.json @@ -48,7 +48,7 @@ "@kbn/shared-ux-router", "@kbn/core-saved-objects-server", "@kbn/share-plugin", - "@kbn/core-http-server", + "@kbn/core-http-server" ], "exclude": [ "target/**/*", From 49849cf42c3d9febdd7ace60888b3c03b637b088 Mon Sep 17 00:00:00 2001 From: Antonio Date: Wed, 9 Aug 2023 17:22:05 +0200 Subject: [PATCH 11/22] [Cases] Fix flaky test in user actions pagination (#163474) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #156750 Fixes #156747 Fixes #156744 Fixes #156743 Fixes #156748 Fixes #156746 Fixes #156745 Fixes #156749 ## Summary Basically what you suggested offline @js-jankisalvi. | Scenario | Old Test | Functional test where it is covered | | ------------- | ------------- | ------------- | | Only shows one list of user actions when `total_user_actions < 10` | `'renders only one action list when user actions are less than or equal to 10'` | `'initially renders user actions list correctly'`| | `Show More` button does not show up when `total_user_actions <= page_size` | `'shows more button visible 21st user action added'` | `'initially renders user actions list correctly'` | | Shows 2 user action lists when `total_user_actions > page_size` | `'renders two user actions list when user actions are more than 10'` | `'shows more actions on button click'` | | loading spinner | `'Loading spinner when user actions loading'` | `'shows more actions on button click'` | ## Flaky Test Runner Let's make sure that the functional tests don't become flaky too. https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2826 --- .../components/user_actions/index.test.tsx | 225 ------------------ .../apps/cases/group1/view_case.ts | 12 + 2 files changed, 12 insertions(+), 225 deletions(-) diff --git a/x-pack/plugins/cases/public/components/user_actions/index.test.tsx b/x-pack/plugins/cases/public/components/user_actions/index.test.tsx index 1d3ba134f7e6d..15c2a8661edb0 100644 --- a/x-pack/plugins/cases/public/components/user_actions/index.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/index.test.tsx @@ -373,229 +373,4 @@ describe.skip(`UserActions`, () => { expect(screen.getAllByText('Damaged Raccoon')[0]).toBeInTheDocument(); }); }); - - // FLAKY: https://github.com/elastic/kibana/issues/156750 - // FLAKY: https://github.com/elastic/kibana/issues/156749 - // FLAKY: https://github.com/elastic/kibana/issues/156748 - // FLAKY: https://github.com/elastic/kibana/issues/156747 - // FLAKY: https://github.com/elastic/kibana/issues/156746 - // FLAKY: https://github.com/elastic/kibana/issues/156745 - // FLAKY: https://github.com/elastic/kibana/issues/156744 - // FLAKY: https://github.com/elastic/kibana/issues/156743 - describe.skip('pagination', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('Loading spinner when user actions loading', () => { - useFindCaseUserActionsMock.mockReturnValue({ isLoading: true }); - useInfiniteFindCaseUserActionsMock.mockReturnValue({ isLoading: true }); - appMockRender.render( - - ); - - expect(screen.getByTestId('user-actions-loading')).toBeInTheDocument(); - }); - - it('renders two user actions list when user actions are more than 10', () => { - appMockRender.render(); - - expect(screen.getAllByTestId('user-actions-list')).toHaveLength(2); - }); - - it('renders only one user actions list when last page is 0', async () => { - useFindCaseUserActionsMock.mockReturnValue({ - ...defaultUseFindCaseUserActions, - data: { userActions: [] }, - }); - const props = { - ...defaultProps, - userActionsStats: { - total: 0, - totalComments: 0, - totalOtherActions: 0, - }, - }; - - appMockRender.render(); - - await waitForComponentToUpdate(); - - expect(screen.getAllByTestId('user-actions-list')).toHaveLength(1); - }); - - it('renders only one user actions list when last page is 1', async () => { - useFindCaseUserActionsMock.mockReturnValue({ - ...defaultUseFindCaseUserActions, - data: { userActions: [] }, - }); - const props = { - ...defaultProps, - userActionsStats: { - total: 1, - totalComments: 0, - totalOtherActions: 1, - }, - }; - - appMockRender.render(); - - await waitForComponentToUpdate(); - - expect(screen.getAllByTestId('user-actions-list')).toHaveLength(1); - }); - - it('renders only one action list when user actions are less than or equal to 10', async () => { - useFindCaseUserActionsMock.mockReturnValue({ - ...defaultUseFindCaseUserActions, - data: { userActions: [] }, - }); - const props = { - ...defaultProps, - userActionsStats: { - total: 10, - totalComments: 6, - totalOtherActions: 4, - }, - }; - - appMockRender.render(); - - await waitForComponentToUpdate(); - - expect(screen.getAllByTestId('user-actions-list')).toHaveLength(1); - }); - - it('call fetchNextPage on showMore button click', async () => { - useInfiniteFindCaseUserActionsMock.mockReturnValue({ - ...defaultInfiniteUseFindCaseUserActions, - hasNextPage: true, - }); - const props = { - ...defaultProps, - userActionsStats: { - total: 25, - totalComments: 10, - totalOtherActions: 15, - }, - }; - - appMockRender.render(); - - await waitForComponentToUpdate(); - - expect(screen.getAllByTestId('user-actions-list')).toHaveLength(2); - - const showMore = screen.getByTestId('cases-show-more-user-actions'); - - expect(showMore).toBeInTheDocument(); - - userEvent.click(showMore); - - await waitFor(() => { - expect(defaultInfiniteUseFindCaseUserActions.fetchNextPage).toHaveBeenCalled(); - }); - }); - - it('shows more button visible 21st user action added', async () => { - const mockUserActions = [ - ...caseUserActions, - getUserAction('comment', UserActionActions.create), - getUserAction('comment', UserActionActions.update), - getUserAction('comment', UserActionActions.create), - getUserAction('comment', UserActionActions.update), - getUserAction('comment', UserActionActions.create), - getUserAction('comment', UserActionActions.update), - getUserAction('comment', UserActionActions.create), - ]; - useInfiniteFindCaseUserActionsMock.mockReturnValue({ - ...defaultInfiniteUseFindCaseUserActions, - data: { - pages: [ - { - total: 20, - page: 1, - perPage: 10, - userActions: mockUserActions, - }, - ], - }, - }); - useFindCaseUserActionsMock.mockReturnValue({ - ...defaultUseFindCaseUserActions, - data: { - total: 20, - page: 2, - perPage: 10, - userActions: mockUserActions, - }, - }); - const props = { - ...defaultProps, - userActionsStats: { - total: 20, - totalComments: 10, - totalOtherActions: 10, - }, - }; - - const { rerender } = appMockRender.render(); - - await waitForComponentToUpdate(); - - expect(screen.getAllByTestId('user-actions-list')).toHaveLength(2); - expect(screen.queryByTestId('cases-show-more-user-actions')).not.toBeInTheDocument(); - - useInfiniteFindCaseUserActionsMock.mockReturnValue({ - ...defaultInfiniteUseFindCaseUserActions, - data: { - pages: [ - { - total: 21, - page: 1, - perPage: 10, - userActions: mockUserActions, - }, - { - total: 21, - page: 2, - perPage: 10, - userActions: [getUserAction('comment', UserActionActions.create)], - }, - ], - }, - hasNextPage: true, - }); - useFindCaseUserActionsMock.mockReturnValue({ - ...defaultUseFindCaseUserActions, - data: { - total: 21, - page: 2, - perPage: 10, - userActions: mockUserActions, - }, - }); - - const newProps = { - ...props, - userActionsStats: { - total: 21, - totalComments: 11, - totalOtherActions: 10, - }, - }; - - rerender(); - - await waitForComponentToUpdate(); - - expect(screen.getAllByTestId('user-actions-list')).toHaveLength(2); - - const firstUserActionsList = screen.getAllByTestId('user-actions-list')[0]; - - expect(firstUserActionsList.getElementsByTagName('li')).toHaveLength(11); - - expect(screen.getByTestId('cases-show-more-user-actions')).toBeInTheDocument(); - }); - }); }); diff --git a/x-pack/test/functional_with_es_ssl/apps/cases/group1/view_case.ts b/x-pack/test/functional_with_es_ssl/apps/cases/group1/view_case.ts index ab4ed59336826..b44f62e71b9a0 100644 --- a/x-pack/test/functional_with_es_ssl/apps/cases/group1/view_case.ts +++ b/x-pack/test/functional_with_es_ssl/apps/cases/group1/view_case.ts @@ -724,6 +724,16 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { await cases.api.deleteAllCases(); }); + it('initially renders user actions list correctly', async () => { + expect(testSubjects.missingOrFail('cases-show-more-user-actions')); + + const userActionsLists = await find.allByCssSelector( + '[data-test-subj="user-actions-list"]' + ); + + expect(userActionsLists).length(1); + }); + it('shows more actions on button click', async () => { await cases.api.generateUserActions({ caseId: createdCase.id, @@ -731,6 +741,8 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { totalUpdates: 4, }); + expect(testSubjects.missingOrFail('user-actions-loading')); + await header.waitUntilLoadingHasFinished(); await testSubjects.click('case-refresh'); From f4856f74784cf5ca2094f2f54a6d86f2aff3335a Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 9 Aug 2023 16:49:57 +0100 Subject: [PATCH 12/22] fix(NA): apply ipv4 first dns result order for worker threads (#163484) This PR is a follow up of https://github.com/elastic/kibana/pull/163025 as we discover the initial fix doesn't apply correctly to working threads during development. --- src/setup_node_env/dns_ipv4_first.js | 13 +++++++++++++ src/setup_node_env/index.js | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 src/setup_node_env/dns_ipv4_first.js diff --git a/src/setup_node_env/dns_ipv4_first.js b/src/setup_node_env/dns_ipv4_first.js new file mode 100644 index 0000000000000..75dd876c46d35 --- /dev/null +++ b/src/setup_node_env/dns_ipv4_first.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +// enables Node 16 default DNS lookup behavior for the current thread +require('dns').setDefaultResultOrder('ipv4first'); + +// overrides current process node options, so it can be restored in worker threads too +process.env.NODE_OPTIONS = `${process.env.NODE_OPTIONS || ''} --dns-result-order=ipv4first`; diff --git a/src/setup_node_env/index.js b/src/setup_node_env/index.js index 4f7babd66ac58..176785e10246a 100644 --- a/src/setup_node_env/index.js +++ b/src/setup_node_env/index.js @@ -10,7 +10,7 @@ require('./setup_env'); // restore < Node 16 default DNS lookup behavior -require('dns').setDefaultResultOrder('ipv4first'); +require('./dns_ipv4_first'); require('@kbn/babel-register').install(); require('./polyfill'); From dc949ee3736105eff3b4f424834dab39393518b1 Mon Sep 17 00:00:00 2001 From: Janki Salvi <117571355+js-jankisalvi@users.noreply.github.com> Date: Wed, 9 Aug 2023 17:52:36 +0200 Subject: [PATCH 13/22] [Cases] Hide cases in stack management UI (#163037) ## Summary fixes https://github.com/elastic/kibana/issues/160337 This PR - hides cases in the serverless Elasticsearch project, cases APIs throw error - throws 403 from API when `owner=cases` for security or observability serverless mode - verifies the behaviour in serverless functional as well as api_integration tests **How to test** - Boot up `es` serverless solution and make sure that `cases` from the navbar is hidden and cannot not be accessible through url as well - Boot up `observability` or `security` serverless solutions and make sure that `cases` is available in the navbar and works fine - Boot up classic kibana and make sure that the left navbar has the same menu entries it always had. ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios https://github.com/elastic/kibana/assets/117571355/20c1974e-44f0-45b0-80aa-e644fec148ff ### For maintainers - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- config/serverless.yml | 3 + .../test_suites/core_plugins/rendering.ts | 1 + x-pack/plugins/cases/common/ui/types.ts | 3 + x-pack/plugins/cases/public/plugin.test.ts | 154 +++++++++++ x-pack/plugins/cases/public/plugin.ts | 50 ++-- x-pack/plugins/cases/server/config.test.ts | 3 + x-pack/plugins/cases/server/config.ts | 3 + x-pack/plugins/cases/server/index.ts | 1 + x-pack/plugins/cases/server/plugin.test.ts | 123 +++++++++ x-pack/plugins/cases/server/plugin.ts | 4 +- x-pack/plugins/cases/tsconfig.json | 1 + .../observability/cases/find_cases.ts | 57 ++++ .../observability/cases/get_case.ts | 38 +++ .../observability/cases/helpers/api.ts | 247 ++++++++++++++++++ .../observability/cases/helpers/omit.ts | 49 ++++ .../observability/cases/post_case.ts | 64 +++++ .../test_suites/observability/index.ts | 3 + .../test_suites/search/cases/find_cases.ts | 23 ++ .../test_suites/search/cases/post_case.ts | 43 +++ .../test_suites/search/index.ts | 2 + .../test_suites/security/cases/find_cases.ts | 60 +++++ .../test_suites/security/cases/get_case.ts | 38 +++ .../test_suites/security/cases/helpers/api.ts | 247 ++++++++++++++++++ .../security/cases/helpers/omit.ts | 49 ++++ .../test_suites/security/cases/post_case.ts | 77 ++++++ .../test_suites/security/index.ts | 3 + .../test_suites/observability/navigation.ts | 17 ++ .../test_suites/search/navigation.ts | 13 + .../test_suites/security/ftr/navigation.ts | 14 + x-pack/test_serverless/tsconfig.json | 1 + 30 files changed, 1366 insertions(+), 25 deletions(-) create mode 100644 x-pack/plugins/cases/public/plugin.test.ts create mode 100644 x-pack/plugins/cases/server/plugin.test.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/cases/find_cases.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/cases/get_case.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/cases/helpers/api.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/cases/helpers/omit.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/cases/post_case.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/search/cases/find_cases.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/search/cases/post_case.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/security/cases/find_cases.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/security/cases/get_case.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/security/cases/helpers/api.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/security/cases/helpers/omit.ts create mode 100644 x-pack/test_serverless/api_integration/test_suites/security/cases/post_case.ts diff --git a/config/serverless.yml b/config/serverless.yml index 43e9b86eb1f4a..7a79f262cea73 100644 --- a/config/serverless.yml +++ b/config/serverless.yml @@ -90,3 +90,6 @@ vis_type_timeseries.readOnly: true vis_type_vislib.readOnly: true vis_type_xy.readOnly: true input_control_vis.readOnly: true + +# Disable cases in stack management +xpack.cases.stack.enabled: false diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 673c092a546a9..f03af110fd866 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -197,6 +197,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'xpack.cases.files.allowedMimeTypes (array)', 'xpack.cases.files.maxSize (number)', 'xpack.cases.markdownPlugins.lens (boolean)', + 'xpack.cases.stack.enabled (boolean)', 'xpack.ccr.ui.enabled (boolean)', 'xpack.cloud.base_url (string)', 'xpack.cloud.cname (string)', diff --git a/x-pack/plugins/cases/common/ui/types.ts b/x-pack/plugins/cases/common/ui/types.ts index 86f32c87ebeeb..e2e453aaaf278 100644 --- a/x-pack/plugins/cases/common/ui/types.ts +++ b/x-pack/plugins/cases/common/ui/types.ts @@ -59,6 +59,9 @@ export interface CasesUiConfigType { maxSize?: number; allowedMimeTypes: string[]; }; + stack: { + enabled: boolean; + }; } export const StatusAll = 'all' as const; diff --git a/x-pack/plugins/cases/public/plugin.test.ts b/x-pack/plugins/cases/public/plugin.test.ts new file mode 100644 index 0000000000000..bb81b7d501c5d --- /dev/null +++ b/x-pack/plugins/cases/public/plugin.test.ts @@ -0,0 +1,154 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { PluginInitializerContext } from '@kbn/core/public'; +import { coreMock } from '@kbn/core/public/mocks'; +import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; +import { featuresPluginMock } from '@kbn/features-plugin/public/mocks'; +import { securityMock } from '@kbn/security-plugin/public/mocks'; +import { managementPluginMock } from '@kbn/management-plugin/public/mocks'; +import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; +import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; +import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; +import { lensPluginMock } from '@kbn/lens-plugin/public/mocks'; +import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks'; +import { mockStorage } from '@kbn/kibana-utils-plugin/public/storage/hashed_item_store/mock'; +import { triggersActionsUiMock } from '@kbn/triggers-actions-ui-plugin/public/mocks'; +import type { CasesPluginSetup, CasesPluginStart } from './types'; +import { CasesUiPlugin } from './plugin'; +import { ALLOWED_MIME_TYPES } from '../common/constants/mime_types'; + +function getConfig(overrides = {}) { + return { + markdownPlugins: { lens: true }, + files: { maxSize: 1, allowedMimeTypes: ALLOWED_MIME_TYPES }, + stack: { enabled: true }, + ...overrides, + }; +} + +describe('Cases Ui Plugin', () => { + let context: PluginInitializerContext; + let plugin: CasesUiPlugin; + let coreSetup: ReturnType; + let coreStart: ReturnType; + let pluginsSetup: jest.Mocked; + let pluginsStart: jest.Mocked; + + beforeEach(() => { + context = coreMock.createPluginInitializerContext(getConfig()); + plugin = new CasesUiPlugin(context); + coreSetup = coreMock.createSetup(); + coreStart = coreMock.createStart(); + + pluginsSetup = { + files: { + filesClientFactory: { asScoped: jest.fn(), asUnscoped: jest.fn() }, + registerFileKind: jest.fn(), + }, + security: securityMock.createSetup(), + management: managementPluginMock.createSetupContract(), + }; + + pluginsStart = { + licensing: licensingMock.createStart(), + uiActions: uiActionsPluginMock.createStartContract(), + files: { + filesClientFactory: { asScoped: jest.fn(), asUnscoped: jest.fn() }, + getAllFindKindDefinitions: jest.fn(), + getFileKindDefinition: jest.fn(), + }, + features: featuresPluginMock.createStart(), + security: securityMock.createStart(), + data: dataPluginMock.createStartContract(), + embeddable: embeddablePluginMock.createStartContract(), + lens: lensPluginMock.createStartContract(), + contentManagement: contentManagementMock.createStartContract(), + storage: { + store: { + getItem: mockStorage.getItem, + setItem: mockStorage.setItem, + removeItem: mockStorage.removeItem, + clear: mockStorage.clear, + }, + get: jest.fn(), + set: jest.fn(), + clear: jest.fn(), + remove: jest.fn(), + }, + triggersActionsUi: triggersActionsUiMock.createStart(), + }; + }); + + describe('setup()', () => { + it('should start setup cases plugin correctly', async () => { + const setup = plugin.setup(coreSetup, pluginsSetup); + + expect(setup).toMatchInlineSnapshot(` + Object { + "attachmentFramework": Object { + "registerExternalReference": [Function], + "registerPersistableState": [Function], + }, + } + `); + }); + + it('should register kibana feature when stack is enabled', async () => { + plugin.setup(coreSetup, pluginsSetup); + + expect( + pluginsSetup.management.sections.section.insightsAndAlerting.registerApp + ).toHaveBeenCalled(); + }); + + it('should not register kibana feature when stack is disabled', async () => { + context = coreMock.createPluginInitializerContext(getConfig({ stack: { enabled: false } })); + const pluginWithStackDisabled = new CasesUiPlugin(context); + + pluginWithStackDisabled.setup(coreSetup, pluginsSetup); + + expect( + pluginsSetup.management.sections.section.insightsAndAlerting.registerApp + ).not.toHaveBeenCalled(); + }); + }); + + describe('start', () => { + it('should start cases plugin correctly', async () => { + const pluginStart = plugin.start(coreStart, pluginsStart); + + expect(pluginStart).toStrictEqual({ + api: { + cases: { + bulkGet: expect.any(Function), + find: expect.any(Function), + getCasesMetrics: expect.any(Function), + getCasesStatus: expect.any(Function), + }, + getRelatedCases: expect.any(Function), + }, + helpers: { + canUseCases: expect.any(Function), + getRuleIdFromEvent: expect.any(Function), + getUICapabilities: expect.any(Function), + groupAlertsByRule: expect.any(Function), + }, + hooks: { + useCasesAddToExistingCaseModal: expect.any(Function), + useCasesAddToNewCaseFlyout: expect.any(Function), + }, + ui: { + getAllCasesSelectorModal: expect.any(Function), + getCases: expect.any(Function), + getCasesContext: expect.any(Function), + getRecentCases: expect.any(Function), + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/cases/public/plugin.ts b/x-pack/plugins/cases/public/plugin.ts index 82d62f2c07da7..f4909f344e7fc 100644 --- a/x-pack/plugins/cases/public/plugin.ts +++ b/x-pack/plugins/cases/public/plugin.ts @@ -75,30 +75,32 @@ export class CasesUiPlugin }); } - plugins.management.sections.section.insightsAndAlerting.registerApp({ - id: APP_ID, - title: APP_TITLE, - order: 1, - async mount(params: ManagementAppMountParams) { - const [coreStart, pluginsStart] = (await core.getStartServices()) as [ - CoreStart, - CasesPluginStart, - unknown - ]; - - const { renderApp } = await import('./application'); - - return renderApp({ - mountParams: params, - coreStart, - pluginsStart, - storage, - kibanaVersion, - externalReferenceAttachmentTypeRegistry, - persistableStateAttachmentTypeRegistry, - }); - }, - }); + if (config.stack.enabled) { + plugins.management.sections.section.insightsAndAlerting.registerApp({ + id: APP_ID, + title: APP_TITLE, + order: 1, + async mount(params: ManagementAppMountParams) { + const [coreStart, pluginsStart] = (await core.getStartServices()) as [ + CoreStart, + CasesPluginStart, + unknown + ]; + + const { renderApp } = await import('./application'); + + return renderApp({ + mountParams: params, + coreStart, + pluginsStart, + storage, + kibanaVersion, + externalReferenceAttachmentTypeRegistry, + persistableStateAttachmentTypeRegistry, + }); + }, + }); + } return { attachmentFramework: { diff --git a/x-pack/plugins/cases/server/config.test.ts b/x-pack/plugins/cases/server/config.test.ts index 54fc42f694bc2..352faac983f29 100644 --- a/x-pack/plugins/cases/server/config.test.ts +++ b/x-pack/plugins/cases/server/config.test.ts @@ -106,6 +106,9 @@ describe('config validation', () => { "markdownPlugins": Object { "lens": true, }, + "stack": Object { + "enabled": true, + }, } `); }); diff --git a/x-pack/plugins/cases/server/config.ts b/x-pack/plugins/cases/server/config.ts index c2daeb73b03de..7e30671ee4734 100644 --- a/x-pack/plugins/cases/server/config.ts +++ b/x-pack/plugins/cases/server/config.ts @@ -20,6 +20,9 @@ export const ConfigSchema = schema.object({ // intentionally not setting a default here so that we can determine if the user set it maxSize: schema.maybe(schema.number({ min: 0 })), }), + stack: schema.object({ + enabled: schema.boolean({ defaultValue: true }), + }), }); export type ConfigType = TypeOf; diff --git a/x-pack/plugins/cases/server/index.ts b/x-pack/plugins/cases/server/index.ts index 62748905f6b82..b1cadb43f147c 100644 --- a/x-pack/plugins/cases/server/index.ts +++ b/x-pack/plugins/cases/server/index.ts @@ -16,6 +16,7 @@ export const config: PluginConfigDescriptor = { exposeToBrowser: { markdownPlugins: true, files: { maxSize: true, allowedMimeTypes: true }, + stack: { enabled: true }, }, deprecations: ({ renameFromRoot }) => [ renameFromRoot('xpack.case.enabled', 'xpack.cases.enabled', { level: 'critical' }), diff --git a/x-pack/plugins/cases/server/plugin.test.ts b/x-pack/plugins/cases/server/plugin.test.ts new file mode 100644 index 0000000000000..255e6ce42af68 --- /dev/null +++ b/x-pack/plugins/cases/server/plugin.test.ts @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { PluginInitializerContext } from '@kbn/core/server'; +import {} from '@kbn/core/server'; +import { coreMock } from '@kbn/core/server/mocks'; +import { usageCollectionPluginMock } from '@kbn/usage-collection-plugin/server/mocks'; +import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; +import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; +import { createFilesSetupMock } from '@kbn/files-plugin/server/mocks'; +import { securityMock } from '@kbn/security-plugin/server/mocks'; +import { makeLensEmbeddableFactory } from '@kbn/lens-plugin/server/embeddable/make_lens_embeddable_factory'; +import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; +import { actionsMock } from '@kbn/actions-plugin/server/mocks'; +import { notificationsMock } from '@kbn/notifications-plugin/server/mocks'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import type { PluginsSetup, PluginsStart } from './plugin'; +import { CasePlugin } from './plugin'; +import type { ConfigType } from './config'; +import { ALLOWED_MIME_TYPES } from '../common/constants/mime_types'; + +function getConfig(overrides = {}) { + return { + markdownPlugins: { lens: true }, + files: { maxSize: 1, allowedMimeTypes: ALLOWED_MIME_TYPES }, + stack: { enabled: true }, + ...overrides, + }; +} + +describe('Cases Plugin', () => { + let context: PluginInitializerContext; + let plugin: CasePlugin; + let coreSetup: ReturnType; + let coreStart: ReturnType; + let pluginsSetup: jest.Mocked; + let pluginsStart: jest.Mocked; + + beforeEach(() => { + context = coreMock.createPluginInitializerContext(getConfig()); + + plugin = new CasePlugin(context); + coreSetup = coreMock.createSetup(); + coreStart = coreMock.createStart(); + + pluginsSetup = { + taskManager: taskManagerMock.createSetup(), + actions: actionsMock.createSetup(), + files: createFilesSetupMock(), + lens: { + lensEmbeddableFactory: makeLensEmbeddableFactory( + () => ({}), + () => ({}), + {} + ), + registerVisualizationMigration: jest.fn(), + }, + security: securityMock.createSetup(), + licensing: licensingMock.createSetup(), + usageCollection: usageCollectionPluginMock.createSetupContract(), + features: featuresPluginMock.createSetup(), + }; + + pluginsStart = { + licensing: licensingMock.createStart(), + actions: actionsMock.createStart(), + files: { fileServiceFactory: { asScoped: jest.fn(), asInternal: jest.fn() } }, + features: featuresPluginMock.createStart(), + security: securityMock.createStart(), + notifications: notificationsMock.createStart(), + ruleRegistry: { getRacClientWithRequest: jest.fn(), alerting: alertsMock.createStart() }, + }; + }); + + describe('setup()', () => { + it('should start setup cases plugin correctly', async () => { + plugin.setup(coreSetup, pluginsSetup); + + expect(context.logger.get().debug).toHaveBeenCalledWith( + `Setting up Case Workflow with core contract [${Object.keys( + coreSetup + )}] and plugins [${Object.keys(pluginsSetup)}]` + ); + }); + + it('should register kibana feature when stack is enabled', async () => { + plugin.setup(coreSetup, pluginsSetup); + + expect(pluginsSetup.features.registerKibanaFeature).toHaveBeenCalled(); + }); + + it('should not register kibana feature when stack is disabled', async () => { + context = coreMock.createPluginInitializerContext( + getConfig({ stack: { enabled: false } }) + ); + const pluginWithStackDisabled = new CasePlugin(context); + + pluginWithStackDisabled.setup(coreSetup, pluginsSetup); + + expect(pluginsSetup.features.registerKibanaFeature).not.toHaveBeenCalled(); + }); + }); + + describe('start', () => { + it('should start cases plugin correctly', async () => { + const pluginStart = plugin.start(coreStart, pluginsStart); + + expect(context.logger.get().debug).toHaveBeenCalledWith(`Starting Case Workflow`); + + expect(pluginStart).toMatchInlineSnapshot(` + Object { + "getCasesClientWithRequest": [Function], + "getExternalReferenceAttachmentTypeRegistry": [Function], + "getPersistableStateAttachmentTypeRegistry": [Function], + } + `); + }); + }); +}); diff --git a/x-pack/plugins/cases/server/plugin.ts b/x-pack/plugins/cases/server/plugin.ts index 0ae005e09b188..510686f1a98bd 100644 --- a/x-pack/plugins/cases/server/plugin.ts +++ b/x-pack/plugins/cases/server/plugin.ts @@ -121,7 +121,9 @@ export class CasePlugin { this.securityPluginSetup = plugins.security; this.lensEmbeddableFactory = plugins.lens.lensEmbeddableFactory; - plugins.features.registerKibanaFeature(getCasesKibanaFeature()); + if (this.caseConfig.stack.enabled) { + plugins.features.registerKibanaFeature(getCasesKibanaFeature()); + } core.savedObjects.registerType( createCaseCommentSavedObjectType({ diff --git a/x-pack/plugins/cases/tsconfig.json b/x-pack/plugins/cases/tsconfig.json index cb82b27d5334d..ccd6e228d6aff 100644 --- a/x-pack/plugins/cases/tsconfig.json +++ b/x-pack/plugins/cases/tsconfig.json @@ -68,6 +68,7 @@ "@kbn/core-theme-browser", "@kbn/serverless", "@kbn/core-http-server", + "@kbn/alerting-plugin", "@kbn/content-management-plugin", ], "exclude": [ diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/cases/find_cases.ts b/x-pack/test_serverless/api_integration/test_suites/observability/cases/find_cases.ts new file mode 100644 index 0000000000000..6f88c0ded2fdd --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/observability/cases/find_cases.ts @@ -0,0 +1,57 @@ +/* + * 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 { FtrProviderContext } from '../../../ftr_provider_context'; +import { + findCases, + createCase, + deleteAllCaseItems, + postCaseReq, + findCasesResp, +} from './helpers/api'; + +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('find_cases', () => { + afterEach(async () => { + await deleteAllCaseItems(es); + }); + + it('should return empty response', async () => { + const cases = await findCases({ supertest }); + expect(cases).to.eql(findCasesResp); + }); + + it('should return cases', async () => { + const a = await createCase(supertest, postCaseReq); + const b = await createCase(supertest, postCaseReq); + const c = await createCase(supertest, postCaseReq); + + const cases = await findCases({ supertest }); + + expect(cases).to.eql({ + ...findCasesResp, + total: 3, + cases: [a, b, c], + count_open_cases: 3, + }); + }); + + it('returns empty response when trying to find cases with owner as cases', async () => { + const cases = await findCases({ supertest, query: { owner: 'cases' } }); + expect(cases).to.eql(findCasesResp); + }); + + it('returns empty response when trying to find cases with owner as securitySolution', async () => { + const cases = await findCases({ supertest, query: { owner: 'securitySolution' } }); + expect(cases).to.eql(findCasesResp); + }); + }); +}; diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/cases/get_case.ts b/x-pack/test_serverless/api_integration/test_suites/observability/cases/get_case.ts new file mode 100644 index 0000000000000..fffc529d2df30 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/observability/cases/get_case.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 { FtrProviderContext } from '../../../ftr_provider_context'; +import { + getCase, + createCase, + deleteCasesByESQuery, + getPostCaseRequest, + postCaseResp, +} from './helpers/api'; +import { removeServerGeneratedPropertiesFromCase } from './helpers/omit'; + +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('get_case', () => { + afterEach(async () => { + await deleteCasesByESQuery(es); + }); + + it('should return a case', async () => { + const postedCase = await createCase(supertest, getPostCaseRequest()); + const theCase = await getCase({ supertest, caseId: postedCase.id, includeComments: true }); + + const data = removeServerGeneratedPropertiesFromCase(theCase); + expect(data).to.eql(postCaseResp()); + expect(data.comments?.length).to.eql(0); + }); + }); +}; diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/cases/helpers/api.ts b/x-pack/test_serverless/api_integration/test_suites/observability/cases/helpers/api.ts new file mode 100644 index 0000000000000..5f196ef3e3372 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/observability/cases/helpers/api.ts @@ -0,0 +1,247 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Client } from '@elastic/elasticsearch'; +import type SuperTest from 'supertest'; +import { ALERTING_CASES_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server/src/saved_objects_index_pattern'; +import { CASES_URL } from '@kbn/cases-plugin/common'; +import { Case, CaseSeverity, CaseStatuses } from '@kbn/cases-plugin/common/types/domain'; +import type { CasePostRequest } from '@kbn/cases-plugin/common/types/api'; +import { ConnectorTypes } from '@kbn/cases-plugin/common/types/domain'; +import { CasesFindResponse } from '@kbn/cases-plugin/common/types/api'; + +export interface User { + username: string; + password: string; + description?: string; + roles: string[]; +} + +export const superUser: User = { + username: 'superuser', + password: 'superuser', + roles: ['superuser'], +}; + +export const setupAuth = ({ + apiCall, + headers, + auth, +}: { + apiCall: SuperTest.Test; + headers: Record; + auth?: { user: User; space: string | null } | null; +}): SuperTest.Test => { + if (!Object.hasOwn(headers, 'Cookie') && auth != null) { + return apiCall.auth(auth.user.username, auth.user.password); + } + + return apiCall; +}; + +export const getSpaceUrlPrefix = (spaceId: string | undefined | null) => { + return spaceId && spaceId !== 'default' ? `/s/${spaceId}` : ``; +}; + +export const deleteAllCaseItems = async (es: Client) => { + await Promise.all([ + deleteCasesByESQuery(es), + deleteCasesUserActions(es), + deleteComments(es), + deleteConfiguration(es), + deleteMappings(es), + ]); +}; + +export const deleteCasesUserActions = async (es: Client): Promise => { + await es.deleteByQuery({ + index: ALERTING_CASES_SAVED_OBJECT_INDEX, + q: 'type:cases-user-actions', + wait_for_completion: true, + refresh: true, + body: {}, + conflicts: 'proceed', + }); +}; + +export const deleteCasesByESQuery = async (es: Client): Promise => { + await es.deleteByQuery({ + index: ALERTING_CASES_SAVED_OBJECT_INDEX, + q: 'type:cases', + wait_for_completion: true, + refresh: true, + body: {}, + conflicts: 'proceed', + }); +}; + +export const deleteComments = async (es: Client): Promise => { + await es.deleteByQuery({ + index: ALERTING_CASES_SAVED_OBJECT_INDEX, + q: 'type:cases-comments', + wait_for_completion: true, + refresh: true, + body: {}, + conflicts: 'proceed', + }); +}; + +export const deleteConfiguration = async (es: Client): Promise => { + await es.deleteByQuery({ + index: ALERTING_CASES_SAVED_OBJECT_INDEX, + q: 'type:cases-configure', + wait_for_completion: true, + refresh: true, + body: {}, + conflicts: 'proceed', + }); +}; + +export const deleteMappings = async (es: Client): Promise => { + await es.deleteByQuery({ + index: ALERTING_CASES_SAVED_OBJECT_INDEX, + q: 'type:cases-connector-mappings', + wait_for_completion: true, + refresh: true, + body: {}, + conflicts: 'proceed', + }); +}; + +export const defaultUser = { email: null, full_name: null, username: 'elastic' }; +/** + * A null filled user will occur when the security plugin is disabled + */ +export const nullUser = { email: null, full_name: null, username: null }; + +export const postCaseReq: CasePostRequest = { + description: 'This is a brand new case of a bad meanie defacing data', + title: 'Super Bad Observability Issue', + tags: ['defacement'], + severity: CaseSeverity.LOW, + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + settings: { + syncAlerts: true, + }, + owner: 'observability', + assignees: [], +}; + +/** + * Return a request for creating a case. + */ +export const getPostCaseRequest = (req?: Partial): CasePostRequest => ({ + ...postCaseReq, + ...req, +}); + +export const postCaseResp = ( + id?: string | null, + req: CasePostRequest = postCaseReq +): Partial => ({ + ...req, + ...(id != null ? { id } : {}), + comments: [], + duration: null, + severity: req.severity ?? CaseSeverity.LOW, + totalAlerts: 0, + totalComment: 0, + closed_by: null, + created_by: defaultUser, + external_service: null, + status: CaseStatuses.open, + updated_by: null, + category: null, +}); + +const findCommon = { + page: 1, + per_page: 20, + total: 0, + count_open_cases: 0, + count_closed_cases: 0, + count_in_progress_cases: 0, +}; + +export const findCasesResp: CasesFindResponse = { + ...findCommon, + cases: [], +}; + +export const createCase = async ( + supertest: SuperTest.SuperTest, + params: CasePostRequest, + expectedHttpCode: number = 200, + auth: { user: User; space: string | null } | null = { user: superUser, space: null }, + headers: Record = {} +): Promise => { + const apiCall = supertest.post(`${CASES_URL}`); + + setupAuth({ apiCall, headers, auth }); + + const response = await apiCall + .set('kbn-xsrf', 'foo') + .set('x-elastic-internal-origin', 'foo') + .set(headers) + .send(params) + .expect(expectedHttpCode); + + return response.body; +}; + +export const findCases = async ({ + supertest, + query = {}, + expectedHttpCode = 200, + auth = { user: superUser, space: null }, +}: { + supertest: SuperTest.SuperTest; + query?: Record; + expectedHttpCode?: number; + auth?: { user: User; space: string | null }; +}): Promise => { + const { body: res } = await supertest + .get(`${getSpaceUrlPrefix(auth.space)}${CASES_URL}/_find`) + .auth(auth.user.username, auth.user.password) + .query({ sortOrder: 'asc', ...query }) + .set('kbn-xsrf', 'foo') + .set('x-elastic-internal-origin', 'foo') + .send() + .expect(expectedHttpCode); + + return res; +}; + +export const getCase = async ({ + supertest, + caseId, + includeComments = false, + expectedHttpCode = 200, + auth = { user: superUser, space: null }, +}: { + supertest: SuperTest.SuperTest; + caseId: string; + includeComments?: boolean; + expectedHttpCode?: number; + auth?: { user: User; space: string | null }; +}): Promise => { + const { body: theCase } = await supertest + .get( + `${getSpaceUrlPrefix(auth?.space)}${CASES_URL}/${caseId}?includeComments=${includeComments}` + ) + .set('kbn-xsrf', 'foo') + .set('x-elastic-internal-origin', 'foo') + .auth(auth.user.username, auth.user.password) + .expect(expectedHttpCode); + + return theCase; +}; diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/cases/helpers/omit.ts b/x-pack/test_serverless/api_integration/test_suites/observability/cases/helpers/omit.ts new file mode 100644 index 0000000000000..b25506bfaebea --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/observability/cases/helpers/omit.ts @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Case, Attachment } from '@kbn/cases-plugin/common/types/domain'; +import { omit } from 'lodash'; + +interface CommonSavedObjectAttributes { + id?: string | null; + created_at?: string | null; + updated_at?: string | null; + version?: string | null; + [key: string]: unknown; +} + +const savedObjectCommonAttributes = ['created_at', 'updated_at', 'version', 'id']; + +export const removeServerGeneratedPropertiesFromObject = ( + object: T, + keys: K[] +): Omit => { + return omit(object, keys); +}; +export const removeServerGeneratedPropertiesFromSavedObject = < + T extends CommonSavedObjectAttributes +>( + attributes: T, + keys: Array = [] +): Omit => { + return removeServerGeneratedPropertiesFromObject(attributes, [ + ...savedObjectCommonAttributes, + ...keys, + ]); +}; + +export const removeServerGeneratedPropertiesFromCase = (theCase: Case): Partial => { + return removeServerGeneratedPropertiesFromSavedObject(theCase, ['closed_at']); +}; + +export const removeServerGeneratedPropertiesFromComments = ( + comments: Attachment[] | undefined +): Array> | undefined => { + return comments?.map((comment) => { + return removeServerGeneratedPropertiesFromSavedObject(comment, []); + }); +}; diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/cases/post_case.ts b/x-pack/test_serverless/api_integration/test_suites/observability/cases/post_case.ts new file mode 100644 index 0000000000000..2bb37149c007f --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/observability/cases/post_case.ts @@ -0,0 +1,64 @@ +/* + * 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 { ConnectorTypes } from '@kbn/cases-plugin/common/types/domain'; + +import { FtrProviderContext } from '../../../ftr_provider_context'; +import { deleteCasesByESQuery, createCase, getPostCaseRequest } from './helpers/api'; + +export default ({ getService }: FtrProviderContext): void => { + const es = getService('es'); + const supertest = getService('supertest'); + + describe('post_case', () => { + afterEach(async () => { + await deleteCasesByESQuery(es); + }); + + it('should create a case', async () => { + expect( + await createCase( + supertest, + getPostCaseRequest({ + connector: { + id: '123', + name: 'Jira', + type: ConnectorTypes.jira, + fields: { issueType: 'Task', priority: 'High', parent: null }, + }, + }), + 200 + ) + ); + }); + + it('should throw 403 when create a case with securitySolution as owner', async () => { + expect( + await createCase( + supertest, + getPostCaseRequest({ + owner: 'securitySolution', + }), + 403 + ) + ); + }); + + it('should throw 403 when create a case with cases as owner', async () => { + expect( + await createCase( + supertest, + getPostCaseRequest({ + owner: 'cases', + }), + 403 + ) + ); + }); + }); +}; diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/index.ts b/x-pack/test_serverless/api_integration/test_suites/observability/index.ts index b235be792ed42..443c9366d751b 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/index.ts @@ -17,5 +17,8 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./threshold_rule/documents_count_fired')); loadTestFile(require.resolve('./threshold_rule/custom_eq_avg_bytes_fired')); loadTestFile(require.resolve('./threshold_rule/group_by_fired')); + loadTestFile(require.resolve('./cases/post_case')); + loadTestFile(require.resolve('./cases/find_cases')); + loadTestFile(require.resolve('./cases/get_case')); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/search/cases/find_cases.ts b/x-pack/test_serverless/api_integration/test_suites/search/cases/find_cases.ts new file mode 100644 index 0000000000000..b847833b30b46 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/search/cases/find_cases.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CASES_URL } from '@kbn/cases-plugin/common/constants'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + + describe('find_cases', () => { + it('403 when calling find cases API', async () => { + await supertest + .get(`${CASES_URL}/_find`) + .set('kbn-xsrf', 'foo') + .set('x-elastic-internal-origin', 'foo') + .expect(403); + }); + }); +}; diff --git a/x-pack/test_serverless/api_integration/test_suites/search/cases/post_case.ts b/x-pack/test_serverless/api_integration/test_suites/search/cases/post_case.ts new file mode 100644 index 0000000000000..4391fa29e0831 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/search/cases/post_case.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CASES_URL } from '@kbn/cases-plugin/common/constants'; +import { CaseSeverity } from '@kbn/cases-plugin/common/types/domain'; +import { ConnectorTypes } from '@kbn/cases-plugin/common/types/domain'; + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + + describe('post_case', () => { + it('403 when trying to create case', async () => { + await supertest + .post(CASES_URL) + .set('kbn-xsrf', 'foo') + .set('x-elastic-internal-origin', 'foo') + .send({ + description: 'This is a brand new case of a bad meanie defacing data', + title: 'Super Bad Observability Issue', + tags: ['defacement'], + severity: CaseSeverity.LOW, + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + settings: { + syncAlerts: true, + }, + owner: 'cases', + assignees: [], + }) + .expect(403); + }); + }); +}; diff --git a/x-pack/test_serverless/api_integration/test_suites/search/index.ts b/x-pack/test_serverless/api_integration/test_suites/search/index.ts index 20c04f741b1ac..13ddf80d5a950 100644 --- a/x-pack/test_serverless/api_integration/test_suites/search/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/search/index.ts @@ -10,5 +10,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('serverless search API', function () { loadTestFile(require.resolve('./snapshot_telemetry')); + loadTestFile(require.resolve('./cases/post_case')); + loadTestFile(require.resolve('./cases/find_cases')); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cases/find_cases.ts b/x-pack/test_serverless/api_integration/test_suites/security/cases/find_cases.ts new file mode 100644 index 0000000000000..07283119aea2f --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/security/cases/find_cases.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +import { + findCases, + createCase, + deleteAllCaseItems, + findCasesResp, + postCaseReq, +} from './helpers/api'; + +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('find_cases', () => { + describe('basic tests', () => { + afterEach(async () => { + await deleteAllCaseItems(es); + }); + + it('should return empty response', async () => { + const cases = await findCases({ supertest }); + expect(cases).to.eql(findCasesResp); + }); + + it('should return cases', async () => { + const a = await createCase(supertest, postCaseReq); + const b = await createCase(supertest, postCaseReq); + const c = await createCase(supertest, postCaseReq); + + const cases = await findCases({ supertest }); + + expect(cases).to.eql({ + ...findCasesResp, + total: 3, + cases: [a, b, c], + count_open_cases: 3, + }); + }); + + it('returns empty response when trying to find cases with owner as cases', async () => { + const cases = await findCases({ supertest, query: { owner: 'cases' } }); + expect(cases).to.eql(findCasesResp); + }); + + it('returns empty response when trying to find cases with owner as observability', async () => { + const cases = await findCases({ supertest, query: { owner: 'observability' } }); + expect(cases).to.eql(findCasesResp); + }); + }); + }); +}; diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cases/get_case.ts b/x-pack/test_serverless/api_integration/test_suites/security/cases/get_case.ts new file mode 100644 index 0000000000000..c8dd9ec867514 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/security/cases/get_case.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 { FtrProviderContext } from '../../../ftr_provider_context'; + +import { + getCase, + createCase, + deleteCasesByESQuery, + getPostCaseRequest, + postCaseResp, +} from './helpers/api'; +import { removeServerGeneratedPropertiesFromCase } from './helpers/omit'; + +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('get_case', () => { + afterEach(async () => { + await deleteCasesByESQuery(es); + }); + + it('should return a case', async () => { + const postedCase = await createCase(supertest, getPostCaseRequest()); + const theCase = await getCase({ supertest, caseId: postedCase.id, includeComments: true }); + + const data = removeServerGeneratedPropertiesFromCase(theCase); + expect(data).to.eql(postCaseResp()); + expect(data.comments?.length).to.eql(0); + }); + }); +}; diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cases/helpers/api.ts b/x-pack/test_serverless/api_integration/test_suites/security/cases/helpers/api.ts new file mode 100644 index 0000000000000..afba9c46c67c2 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/security/cases/helpers/api.ts @@ -0,0 +1,247 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Client } from '@elastic/elasticsearch'; +import type SuperTest from 'supertest'; +import { ALERTING_CASES_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server/src/saved_objects_index_pattern'; +import { CASES_URL } from '@kbn/cases-plugin/common'; +import { Case, CaseSeverity, CaseStatuses } from '@kbn/cases-plugin/common/types/domain'; +import type { CasePostRequest } from '@kbn/cases-plugin/common/types/api'; +import { ConnectorTypes } from '@kbn/cases-plugin/common/types/domain'; +import { CasesFindResponse } from '@kbn/cases-plugin/common/types/api'; + +export interface User { + username: string; + password: string; + description?: string; + roles: string[]; +} + +export const superUser: User = { + username: 'superuser', + password: 'superuser', + roles: ['superuser'], +}; + +export const setupAuth = ({ + apiCall, + headers, + auth, +}: { + apiCall: SuperTest.Test; + headers: Record; + auth?: { user: User; space: string | null } | null; +}): SuperTest.Test => { + if (!Object.hasOwn(headers, 'Cookie') && auth != null) { + return apiCall.auth(auth.user.username, auth.user.password); + } + + return apiCall; +}; + +export const getSpaceUrlPrefix = (spaceId: string | undefined | null) => { + return spaceId && spaceId !== 'default' ? `/s/${spaceId}` : ``; +}; + +export const deleteAllCaseItems = async (es: Client) => { + await Promise.all([ + deleteCasesByESQuery(es), + deleteCasesUserActions(es), + deleteComments(es), + deleteConfiguration(es), + deleteMappings(es), + ]); +}; + +export const deleteCasesUserActions = async (es: Client): Promise => { + await es.deleteByQuery({ + index: ALERTING_CASES_SAVED_OBJECT_INDEX, + q: 'type:cases-user-actions', + wait_for_completion: true, + refresh: true, + body: {}, + conflicts: 'proceed', + }); +}; + +export const deleteCasesByESQuery = async (es: Client): Promise => { + await es.deleteByQuery({ + index: ALERTING_CASES_SAVED_OBJECT_INDEX, + q: 'type:cases', + wait_for_completion: true, + refresh: true, + body: {}, + conflicts: 'proceed', + }); +}; + +export const deleteComments = async (es: Client): Promise => { + await es.deleteByQuery({ + index: ALERTING_CASES_SAVED_OBJECT_INDEX, + q: 'type:cases-comments', + wait_for_completion: true, + refresh: true, + body: {}, + conflicts: 'proceed', + }); +}; + +export const deleteConfiguration = async (es: Client): Promise => { + await es.deleteByQuery({ + index: ALERTING_CASES_SAVED_OBJECT_INDEX, + q: 'type:cases-configure', + wait_for_completion: true, + refresh: true, + body: {}, + conflicts: 'proceed', + }); +}; + +export const deleteMappings = async (es: Client): Promise => { + await es.deleteByQuery({ + index: ALERTING_CASES_SAVED_OBJECT_INDEX, + q: 'type:cases-connector-mappings', + wait_for_completion: true, + refresh: true, + body: {}, + conflicts: 'proceed', + }); +}; + +export const defaultUser = { email: null, full_name: null, username: 'elastic' }; +/** + * A null filled user will occur when the security plugin is disabled + */ +export const nullUser = { email: null, full_name: null, username: null }; + +export const postCaseReq: CasePostRequest = { + description: 'This is a brand new case of a bad meanie defacing data', + title: 'Super Bad Observability Issue', + tags: ['defacement'], + severity: CaseSeverity.LOW, + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + settings: { + syncAlerts: true, + }, + owner: 'securitySolution', + assignees: [], +}; + +/** + * Return a request for creating a case. + */ +export const getPostCaseRequest = (req?: Partial): CasePostRequest => ({ + ...postCaseReq, + ...req, +}); + +export const postCaseResp = ( + id?: string | null, + req: CasePostRequest = postCaseReq +): Partial => ({ + ...req, + ...(id != null ? { id } : {}), + comments: [], + duration: null, + severity: req.severity ?? CaseSeverity.LOW, + totalAlerts: 0, + totalComment: 0, + closed_by: null, + created_by: defaultUser, + external_service: null, + status: CaseStatuses.open, + updated_by: null, + category: null, +}); + +const findCommon = { + page: 1, + per_page: 20, + total: 0, + count_open_cases: 0, + count_closed_cases: 0, + count_in_progress_cases: 0, +}; + +export const findCasesResp: CasesFindResponse = { + ...findCommon, + cases: [], +}; + +export const createCase = async ( + supertest: SuperTest.SuperTest, + params: CasePostRequest, + expectedHttpCode: number = 200, + auth: { user: User; space: string | null } | null = { user: superUser, space: null }, + headers: Record = {} +): Promise => { + const apiCall = supertest.post(`${CASES_URL}`); + + setupAuth({ apiCall, headers, auth }); + + const { body: theCase } = await apiCall + .set('kbn-xsrf', 'foo') + .set('x-elastic-internal-origin', 'foo') + .set(headers) + .send(params) + .expect(expectedHttpCode); + + return theCase; +}; + +export const findCases = async ({ + supertest, + query = {}, + expectedHttpCode = 200, + auth = { user: superUser, space: null }, +}: { + supertest: SuperTest.SuperTest; + query?: Record; + expectedHttpCode?: number; + auth?: { user: User; space: string | null }; +}): Promise => { + const { body: res } = await supertest + .get(`${getSpaceUrlPrefix(auth.space)}${CASES_URL}/_find`) + .auth(auth.user.username, auth.user.password) + .query({ sortOrder: 'asc', ...query }) + .set('kbn-xsrf', 'foo') + .set('x-elastic-internal-origin', 'foo') + .send() + .expect(expectedHttpCode); + + return res; +}; + +export const getCase = async ({ + supertest, + caseId, + includeComments = false, + expectedHttpCode = 200, + auth = { user: superUser, space: null }, +}: { + supertest: SuperTest.SuperTest; + caseId: string; + includeComments?: boolean; + expectedHttpCode?: number; + auth?: { user: User; space: string | null }; +}): Promise => { + const { body: theCase } = await supertest + .get( + `${getSpaceUrlPrefix(auth?.space)}${CASES_URL}/${caseId}?includeComments=${includeComments}` + ) + .set('kbn-xsrf', 'foo') + .set('x-elastic-internal-origin', 'foo') + .auth(auth.user.username, auth.user.password) + .expect(expectedHttpCode); + + return theCase; +}; diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cases/helpers/omit.ts b/x-pack/test_serverless/api_integration/test_suites/security/cases/helpers/omit.ts new file mode 100644 index 0000000000000..b25506bfaebea --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/security/cases/helpers/omit.ts @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Case, Attachment } from '@kbn/cases-plugin/common/types/domain'; +import { omit } from 'lodash'; + +interface CommonSavedObjectAttributes { + id?: string | null; + created_at?: string | null; + updated_at?: string | null; + version?: string | null; + [key: string]: unknown; +} + +const savedObjectCommonAttributes = ['created_at', 'updated_at', 'version', 'id']; + +export const removeServerGeneratedPropertiesFromObject = ( + object: T, + keys: K[] +): Omit => { + return omit(object, keys); +}; +export const removeServerGeneratedPropertiesFromSavedObject = < + T extends CommonSavedObjectAttributes +>( + attributes: T, + keys: Array = [] +): Omit => { + return removeServerGeneratedPropertiesFromObject(attributes, [ + ...savedObjectCommonAttributes, + ...keys, + ]); +}; + +export const removeServerGeneratedPropertiesFromCase = (theCase: Case): Partial => { + return removeServerGeneratedPropertiesFromSavedObject(theCase, ['closed_at']); +}; + +export const removeServerGeneratedPropertiesFromComments = ( + comments: Attachment[] | undefined +): Array> | undefined => { + return comments?.map((comment) => { + return removeServerGeneratedPropertiesFromSavedObject(comment, []); + }); +}; diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cases/post_case.ts b/x-pack/test_serverless/api_integration/test_suites/security/cases/post_case.ts new file mode 100644 index 0000000000000..1d49545c3d53a --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/security/cases/post_case.ts @@ -0,0 +1,77 @@ +/* + * 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 { ConnectorTypes } from '@kbn/cases-plugin/common/types/domain'; + +import { FtrProviderContext } from '../../../ftr_provider_context'; +import { deleteCasesByESQuery, createCase, getPostCaseRequest, postCaseResp } from './helpers/api'; +import { removeServerGeneratedPropertiesFromCase } from './helpers/omit'; + +export default ({ getService }: FtrProviderContext): void => { + const es = getService('es'); + const supertest = getService('supertest'); + + describe('post_case', () => { + afterEach(async () => { + await deleteCasesByESQuery(es); + }); + + it('should create a case', async () => { + const postedCase = await createCase( + supertest, + getPostCaseRequest({ + connector: { + id: '123', + name: 'Jira', + type: ConnectorTypes.jira, + fields: { issueType: 'Task', priority: 'High', parent: null }, + }, + }) + ); + const data = removeServerGeneratedPropertiesFromCase(postedCase); + + expect(data).to.eql( + postCaseResp( + null, + getPostCaseRequest({ + connector: { + id: '123', + name: 'Jira', + type: ConnectorTypes.jira, + fields: { issueType: 'Task', priority: 'High', parent: null }, + }, + }) + ) + ); + }); + + it('should throw 403 when trying to create a case with observability as owner', async () => { + expect( + await createCase( + supertest, + getPostCaseRequest({ + owner: 'observability', + }), + 403 + ) + ); + }); + + it('should throw 403 when trying to create a case with cases as owner', async () => { + expect( + await createCase( + supertest, + getPostCaseRequest({ + owner: 'cases', + }), + 403 + ) + ); + }); + }); +}; diff --git a/x-pack/test_serverless/api_integration/test_suites/security/index.ts b/x-pack/test_serverless/api_integration/test_suites/security/index.ts index a57d4446e4b9b..294f4b32af5e6 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/index.ts @@ -11,5 +11,8 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('serverless security API', function () { loadTestFile(require.resolve('./fleet')); loadTestFile(require.resolve('./snapshot_telemetry')); + loadTestFile(require.resolve('./cases/post_case')); + loadTestFile(require.resolve('./cases/find_cases')); + loadTestFile(require.resolve('./cases/get_case')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/observability/navigation.ts b/x-pack/test_serverless/functional/test_suites/observability/navigation.ts index 6c90a2a410b61..2054e8eb011f6 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/navigation.ts @@ -86,5 +86,22 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await expect(await browser.getCurrentUrl()).contain('/app/discover#/p/log-explorer'); }); + + it('shows cases in sidebar navigation', async () => { + await svlCommonNavigation.expectExists(); + + await svlCommonNavigation.sidenav.expectLinkExists({ + deepLinkId: 'observability-overview:cases', + }); + }); + + it('navigates to cases app', async () => { + await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'observability-overview:cases' }); + + await svlCommonNavigation.sidenav.expectLinkActive({ + deepLinkId: 'observability-overview:cases', + }); + expect(await browser.getCurrentUrl()).contain('/app/observability/cases'); + }); }); } diff --git a/x-pack/test_serverless/functional/test_suites/search/navigation.ts b/x-pack/test_serverless/functional/test_suites/search/navigation.ts index edf4c41274403..ba19e7b756073 100644 --- a/x-pack/test_serverless/functional/test_suites/search/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/search/navigation.ts @@ -74,5 +74,18 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await expect(await browser.getCurrentUrl()).contain('/app/discover'); }); + + it('does not show cases in sidebar navigation', async () => { + await svlSearchLandingPage.assertSvlSearchSideNavExists(); + + expect(await testSubjects.missingOrFail('cases')); + }); + + it('does not navigate to cases app', async () => { + await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'discover' }); + + expect(await browser.getCurrentUrl()).not.contain('/app/management/cases'); + await testSubjects.missingOrFail('cases-all-title'); + }); }); } diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts index 1ea8ed53c0ca4..695336b7734fb 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts @@ -43,5 +43,19 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await expect(await browser.getCurrentUrl()).contain('app/security/dashboards'); }); + + it('shows cases in sidebar navigation', async () => { + await svlSecLandingPage.assertSvlSecSideNavExists(); + await svlCommonNavigation.expectExists(); + + expect(await testSubjects.existOrFail('solutionSideNavItemLink-cases')); + }); + + it('navigates to cases app', async () => { + await testSubjects.click('solutionSideNavItemLink-cases'); + + expect(await browser.getCurrentUrl()).contain('/app/security/cases'); + await testSubjects.existOrFail('cases-all-title'); + }); }); } diff --git a/x-pack/test_serverless/tsconfig.json b/x-pack/test_serverless/tsconfig.json index 8c431b2537986..eb69a37884039 100644 --- a/x-pack/test_serverless/tsconfig.json +++ b/x-pack/test_serverless/tsconfig.json @@ -46,5 +46,6 @@ "@kbn/test-subj-selector", "@kbn/core-http-common", "@kbn/data-views-plugin", + "@kbn/core-saved-objects-server", ] } From e2b10cb831c506d898a6ffba7f5f8a776439586c Mon Sep 17 00:00:00 2001 From: Konrad Szwarc Date: Wed, 9 Aug 2023 17:59:28 +0200 Subject: [PATCH 14/22] [Fleet][Kafka Output] Tweaks for Kafka UI/API (#162875) 1. Removed Kerberos option from auth type selection 2. Used EuiFieldPassword component for password input State: ![Screenshot 2023-08-01 at 11 16 30](https://github.com/elastic/kibana/assets/29123534/3ef0b3f8-c98b-42d0-9645-fdb6437859f5) 3. Added `None` authentication option. This will save `auth_type` as `none` and won't pass `usernamer`, `password` nor `ssl` to the SO. ![Screenshot 2023-08-02 at 15 59 08](https://github.com/elastic/kibana/assets/29123534/9bbe9ce7-2749-484f-833d-72d1c9e5ee46) 4. Renamed `broker_ack_reliability` to `required_acks` in UI and API. Changed value type to `1 || 0 || -1` 5. Renamed `broker_buffer_size` to `channel_buffer_size` in UI and API. 6. Temporarily disabled `password` field encryption. 7. `partition` key stored in yaml follows proper requirements 8. `topics` key stored in yaml follows proper requirements --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../current_mappings.json | 31 +- .../group2/check_registered_types.test.ts | 2 +- .../plugins/fleet/common/constants/output.ts | 25 +- .../plugins/fleet/common/openapi/bundled.json | 42 +- .../plugins/fleet/common/openapi/bundled.yaml | 32 +- .../schemas/output_create_request_kafka.yaml | 10 +- .../schemas/output_update_request_kafka.yaml | 10 +- .../fleet/common/types/models/output.ts | 9 +- .../cypress/e2e/fleet_settings_outputs.cy.ts | 561 +++++++++--------- x-pack/plugins/fleet/cypress/screens/fleet.ts | 6 +- .../fleet/cypress/screens/fleet_outputs.ts | 31 +- .../edit_output_flyout/index.test.tsx | 6 +- .../edit_output_flyout/output_form_kafka.tsx | 7 +- .../output_form_kafka_authentication.tsx | 203 +++++-- .../output_form_kafka_broker.tsx | 46 +- .../output_form_kafka_headers.tsx | 5 +- .../output_form_kafka_topics.tsx | 50 +- .../output_form_validators.test.tsx | 62 ++ .../output_form_validators.tsx | 97 +++ .../edit_output_flyout/use_output_form.tsx | 95 ++- .../plugins/fleet/public/hooks/use_input.ts | 23 +- .../fleet/server/saved_objects/index.ts | 44 ++ .../migrations/to_v8_10_0.test.ts | 62 ++ .../saved_objects/migrations/to_v8_10_0.ts | 44 ++ .../agent_policies/full_agent_policy.ts | 69 ++- .../fleet/server/services/output.test.ts | 79 ++- .../plugins/fleet/server/services/output.ts | 40 +- .../fleet/server/types/models/output.test.ts | 20 +- .../fleet/server/types/models/output.ts | 58 +- .../fleet/server/types/so_attributes.ts | 5 +- .../apis/outputs/crud.ts | 24 +- 31 files changed, 1249 insertions(+), 549 deletions(-) create mode 100644 x-pack/plugins/fleet/server/saved_objects/migrations/to_v8_10_0.test.ts create mode 100644 x-pack/plugins/fleet/server/saved_objects/migrations/to_v8_10_0.ts diff --git a/packages/kbn-check-mappings-update-cli/current_mappings.json b/packages/kbn-check-mappings-update-cli/current_mappings.json index 748b27fe13dd1..c2c9022b42b2a 100644 --- a/packages/kbn-check-mappings-update-cli/current_mappings.json +++ b/packages/kbn-check-mappings-update-cli/current_mappings.json @@ -629,17 +629,6 @@ } } }, - "search": { - "dynamic": false, - "properties": { - "title": { - "type": "text" - }, - "description": { - "type": "text" - } - } - }, "alert": { "dynamic": false, "properties": { @@ -931,6 +920,17 @@ } } }, + "search": { + "dynamic": false, + "properties": { + "title": { + "type": "text" + }, + "description": { + "type": "text" + } + } + }, "visualization": { "dynamic": false, "properties": { @@ -1657,6 +1657,9 @@ "auth_type": { "type": "keyword" }, + "connection_type": { + "type": "keyword" + }, "username": { "type": "keyword" }, @@ -1743,6 +1746,12 @@ }, "broker_buffer_size": { "type": "integer" + }, + "required_acks": { + "type": "integer" + }, + "channel_buffer_size": { + "type": "integer" } } }, diff --git a/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts index c5ce6a38d9dc9..d0b9d01272b24 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts @@ -105,7 +105,7 @@ describe('checking migration metadata changes on all registered SO types', () => "infrastructure-ui-source": "113182d6895764378dfe7fa9fa027244f3a457c4", "ingest-agent-policies": "f11cc19275f4c3e4ee7c5cd6423b6706b21b989d", "ingest-download-sources": "d7edc5e588d9afa61c4b831604582891c54ef1c7", - "ingest-outputs": "bffa0fd93dfdde904d7f5aff77df72d1c35938d9", + "ingest-outputs": "b4e636b13a5d0f89f0400fb67811d4cca4736eb0", "ingest-package-policies": "55816507db0134b8efbe0509e311a91ce7e1c6cc", "ingest_manager_settings": "418311b03c8eda53f5d2ea6f54c1356afaa65511", "inventory-view": "b8683c8e352a286b4aca1ab21003115a4800af83", diff --git a/x-pack/plugins/fleet/common/constants/output.ts b/x-pack/plugins/fleet/common/constants/output.ts index b23fbc3cc2c2a..59f3ceff36a0f 100644 --- a/x-pack/plugins/fleet/common/constants/output.ts +++ b/x-pack/plugins/fleet/common/constants/output.ts @@ -42,6 +42,12 @@ export const kafkaAuthType = { Userpass: 'user_pass', Ssl: 'ssl', Kerberos: 'kerberos', + None: 'none', +} as const; + +export const kafkaConnectionType = { + Plaintext: 'plaintext', + Encryption: 'encryption', } as const; export const kafkaSaslMechanism = { @@ -60,18 +66,19 @@ export const kafkaTopicWhenType = { Equals: 'equals', Contains: 'contains', Regexp: 'regexp', - Range: 'range', - Network: 'network', - HasFields: 'has_fields', - Or: 'or', - And: 'and', - Not: 'not', } as const; export const kafkaAcknowledgeReliabilityLevel = { - Commit: 'Wait for local commit', - Replica: 'Wait for all replicas to commit', - DoNotWait: 'Do not wait', + Commit: 1, + Replica: -1, + DoNotWait: 0, +} as const; + +export const kafkaVerificationModes = { + Full: 'full', + None: 'none', + Strict: 'strict', + Certificate: 'certificate', } as const; export const kafkaSupportedVersions = [ diff --git a/x-pack/plugins/fleet/common/openapi/bundled.json b/x-pack/plugins/fleet/common/openapi/bundled.json index cc1ad5c98c32a..200cebba48cc7 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.json +++ b/x-pack/plugins/fleet/common/openapi/bundled.json @@ -7701,6 +7701,15 @@ }, "key": { "type": "string" + }, + "verification_mode": { + "type": "string", + "enum": [ + "none", + "full", + "certificate", + "strict" + ] } } }, @@ -7751,6 +7760,13 @@ "auth_type": { "type": "string" }, + "connection_type": { + "type": "string", + "enum": [ + "plaintext", + "encryption" + ] + }, "username": { "type": "string" }, @@ -7826,11 +7842,8 @@ "broker_timeout": { "type": "number" }, - "broker_buffer_size": { + "required_acks": { "type": "number" - }, - "broker_ack_reliability": { - "type": "string" } }, "required": [ @@ -8103,6 +8116,15 @@ }, "key": { "type": "string" + }, + "verification_mode": { + "type": "string", + "enum": [ + "none", + "full", + "certificate", + "strict" + ] } } }, @@ -8153,6 +8175,13 @@ "auth_type": { "type": "string" }, + "connection_type": { + "type": "string", + "enum": [ + "plaintext", + "encryption" + ] + }, "username": { "type": "string" }, @@ -8228,10 +8257,7 @@ "broker_timeout": { "type": "number" }, - "broker_ack_reliability": { - "type": "string" - }, - "broker_buffer_size": { + "required_acks": { "type": "number" } }, diff --git a/x-pack/plugins/fleet/common/openapi/bundled.yaml b/x-pack/plugins/fleet/common/openapi/bundled.yaml index 0d72245fa2d99..6c216e464a104 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.yaml +++ b/x-pack/plugins/fleet/common/openapi/bundled.yaml @@ -4959,6 +4959,13 @@ components: type: string key: type: string + verification_mode: + type: string + enum: + - none + - full + - certificate + - strict proxy_id: type: string shipper: @@ -4990,6 +4997,11 @@ components: type: string auth_type: type: string + connection_type: + type: string + enum: + - plaintext + - encryption username: type: string password: @@ -5038,10 +5050,8 @@ components: type: number broker_timeout: type: number - broker_buffer_size: + required_acks: type: number - broker_ack_reliability: - type: string required: - name - type @@ -5223,6 +5233,13 @@ components: type: string key: type: string + verification_mode: + type: string + enum: + - none + - full + - certificate + - strict proxy_id: type: string shipper: @@ -5254,6 +5271,11 @@ components: type: string auth_type: type: string + connection_type: + type: string + enum: + - plaintext + - encryption username: type: string password: @@ -5302,9 +5324,7 @@ components: type: number broker_timeout: type: number - broker_ack_reliability: - type: string - broker_buffer_size: + required_acks: type: number required: - name diff --git a/x-pack/plugins/fleet/common/openapi/components/schemas/output_create_request_kafka.yaml b/x-pack/plugins/fleet/common/openapi/components/schemas/output_create_request_kafka.yaml index dbed2b44dc08a..fa76c2301ed94 100644 --- a/x-pack/plugins/fleet/common/openapi/components/schemas/output_create_request_kafka.yaml +++ b/x-pack/plugins/fleet/common/openapi/components/schemas/output_create_request_kafka.yaml @@ -35,6 +35,9 @@ properties: type: string key: type: string + verification_mode: + type: string + enum: ['none', 'full', 'certificate', 'strict'] proxy_id: type: string shipper: @@ -66,6 +69,9 @@ properties: type: string auth_type: type: string + connection_type: + type: string + enum: ['plaintext', 'encryption'] username: type: string password: @@ -114,10 +120,8 @@ properties: type: number broker_timeout: type: number - broker_buffer_size: + required_acks: type: number - broker_ack_reliability: - type: string required: - name - type diff --git a/x-pack/plugins/fleet/common/openapi/components/schemas/output_update_request_kafka.yaml b/x-pack/plugins/fleet/common/openapi/components/schemas/output_update_request_kafka.yaml index bb1e76fa70a55..2ce5525a1a9f4 100644 --- a/x-pack/plugins/fleet/common/openapi/components/schemas/output_update_request_kafka.yaml +++ b/x-pack/plugins/fleet/common/openapi/components/schemas/output_update_request_kafka.yaml @@ -35,6 +35,9 @@ properties: type: string key: type: string + verification_mode: + type: string + enum: ['none', 'full', 'certificate', 'strict'] proxy_id: type: string shipper: @@ -66,6 +69,9 @@ properties: type: string auth_type: type: string + connection_type: + type: string + enum: ['plaintext', 'encryption'] username: type: string password: @@ -114,9 +120,7 @@ properties: type: number broker_timeout: type: number - broker_ack_reliability: - type: string - broker_buffer_size: + required_acks: type: number required: - name diff --git a/x-pack/plugins/fleet/common/types/models/output.ts b/x-pack/plugins/fleet/common/types/models/output.ts index 95f353575afd6..a537e0ab0233b 100644 --- a/x-pack/plugins/fleet/common/types/models/output.ts +++ b/x-pack/plugins/fleet/common/types/models/output.ts @@ -11,14 +11,18 @@ import type { kafkaAuthType, kafkaCompressionType, kafkaSaslMechanism } from '.. import type { kafkaPartitionType } from '../../constants'; import type { kafkaTopicWhenType } from '../../constants'; import type { kafkaAcknowledgeReliabilityLevel } from '../../constants'; +import type { kafkaVerificationModes } from '../../constants'; +import type { kafkaConnectionType } from '../../constants'; export type OutputType = typeof outputType; export type KafkaCompressionType = typeof kafkaCompressionType; export type KafkaAuthType = typeof kafkaAuthType; +export type KafkaConnectionTypeType = typeof kafkaConnectionType; export type KafkaSaslMechanism = typeof kafkaSaslMechanism; export type KafkaPartitionType = typeof kafkaPartitionType; export type KafkaTopicWhenType = typeof kafkaTopicWhenType; export type KafkaAcknowledgeReliabilityLevel = typeof kafkaAcknowledgeReliabilityLevel; +export type KafkaVerificationMode = typeof kafkaVerificationModes; interface NewBaseOutput { is_default: boolean; @@ -34,6 +38,7 @@ interface NewBaseOutput { certificate_authorities?: string[]; certificate?: string; key?: string; + verification_mode?: ValueOf; } | null; proxy_id?: string | null; shipper?: ShipperOutput | null; @@ -76,6 +81,7 @@ export interface KafkaOutput extends NewBaseOutput { compression?: ValueOf; compression_level?: number; auth_type?: ValueOf; + connection_type?: ValueOf; username?: string; password?: string; sasl?: { @@ -105,6 +111,5 @@ export interface KafkaOutput extends NewBaseOutput { }>; timeout?: number; broker_timeout?: number; - broker_ack_reliability?: ValueOf; - broker_buffer_size?: number; + required_acks?: ValueOf; } diff --git a/x-pack/plugins/fleet/cypress/e2e/fleet_settings_outputs.cy.ts b/x-pack/plugins/fleet/cypress/e2e/fleet_settings_outputs.cy.ts index 45ff5257fc7c2..2d9f33d8e1efa 100644 --- a/x-pack/plugins/fleet/cypress/e2e/fleet_settings_outputs.cy.ts +++ b/x-pack/plugins/fleet/cypress/e2e/fleet_settings_outputs.cy.ts @@ -5,10 +5,6 @@ * 2.0. */ -import { allowedExperimentalValues } from '../../common/experimental_features'; - -import { ExperimentalFeaturesService } from '../../public/services'; - import { getSpecificSelectorId, SETTINGS_CONFIRM_MODAL_BTN, @@ -42,323 +38,358 @@ describe('Outputs', () => { }); describe('Kafka', () => { - ExperimentalFeaturesService.init(allowedExperimentalValues); - - const { kafkaOutput: isKafkaOutputEnabled } = ExperimentalFeaturesService.get(); - - // TODO: Remove IF statement once Kafka is GA - if (!isKafkaOutputEnabled) { - it('is not available', () => { - visit('/app/fleet/settings'); - }); - } else { - describe('Form validation', () => { - it('renders all form fields', () => { - selectKafkaOutput(); - - cy.getBySel(SETTINGS_OUTPUTS.NAME_INPUT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.VERSION_SELECT); - cy.get('[placeholder="Specify host"'); - cy.getBySel(SETTINGS_OUTPUTS.ADD_HOST_ROW_BTN); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SELECT).within(() => { - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_PASSWORD_OPTION); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SSL_OPTION); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_KERBEROS_OPTION); - }); - - // Verify user/pass fields - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_INPUT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_PASSWORD_INPUT); - - // Verify SSL fields - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SSL_OPTION).click(); - cy.get('[placeholder="Specify certificate authority"]'); - cy.get('[placeholder="Specify ssl certificate"]'); - cy.get('[placeholder="Specify certificate key"]'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_PASSWORD_OPTION).click(); - - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SASL_SELECT).within(() => { - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SASL_PLAIN_OPTION); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SASL_SCRAM_256_OPTION); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SASL_SCRAM_512_OPTION); - }); + describe('Form validation', () => { + it('renders all form fields', () => { + selectKafkaOutput(); + + cy.getBySel(SETTINGS_OUTPUTS.NAME_INPUT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.VERSION_SELECT); + cy.get('[placeholder="Specify host"'); + cy.getBySel(SETTINGS_OUTPUTS.ADD_HOST_ROW_BTN); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SELECT).within(() => { + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_NONE_OPTION); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_PASSWORD_OPTION); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SSL_OPTION); + }); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_PANEL).within(() => { - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_SELECT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_RANDOM_OPTION); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_HASH_OPTION); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_ROUND_ROBIN_OPTION); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_EVENTS_INPUT); - }); + // Verify user/pass fields + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_INPUT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_PASSWORD_INPUT); + cy.get('[placeholder="Specify certificate authority"]'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_VERIFICATION_MODE_INPUT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_CONNECTION_TYPE_SELECT).should( + 'not.exist' + ); + + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SASL_SELECT).within(() => { + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SASL_PLAIN_OPTION); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SASL_SCRAM_256_OPTION); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SASL_SCRAM_512_OPTION); + }); - // Verify Round Robin fields - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_RANDOM_OPTION).click(); + // Verify SSL fields + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SSL_OPTION).click(); + cy.get('[placeholder="Specify certificate authority"]'); + cy.get('[placeholder="Specify ssl certificate"]'); + cy.get('[placeholder="Specify certificate key"]'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_VERIFICATION_MODE_INPUT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_CONNECTION_TYPE_SELECT).should( + 'not.exist' + ); + + // Verify None fields + + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_NONE_OPTION).click(); + + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SASL_SELECT).should('not.exist'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_INPUT).should('not.exist'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_PASSWORD_INPUT).should('not.exist'); + cy.get('[placeholder="Specify ssl certificate"]').should('not.exist'); + cy.get('[placeholder="Specify certificate key"]').should('not.exist'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_VERIFICATION_MODE_INPUT).should( + 'not.exist' + ); + cy.get('[placeholder="Specify certificate authority"]').should('not.exist'); + + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_CONNECTION_TYPE_SELECT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_CONNECTION_TYPE_PLAIN_OPTION); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_CONNECTION_TYPE_ENCRYPTION_OPTION); + + cy.getBySel( + SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_CONNECTION_TYPE_ENCRYPTION_OPTION + ).click(); + + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_VERIFICATION_MODE_INPUT); + cy.get('[placeholder="Specify certificate authority"]'); + + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_PASSWORD_OPTION).click(); + + // Verify Partitioning fields + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_PANEL).within(() => { + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_SELECT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_RANDOM_OPTION); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_HASH_OPTION); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_ROUND_ROBIN_OPTION); cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_EVENTS_INPUT); + }); - // Verify Hash fields - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_HASH_OPTION).click(); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_HASH_INPUT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_RANDOM_OPTION).click(); - - // Topics - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_PANEL).within(() => { - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_DEFAULT_TOPIC_INPUT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_ADD_ROW_BUTTON); - }); + // Verify Round Robin fields + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_RANDOM_OPTION).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_EVENTS_INPUT); - // Verify one topic processor fields - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_ADD_ROW_BUTTON).click(); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_TOPIC_INPUT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_CONDITION_INPUT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_WHEN_INPUT); - - // Verify additional topic processor fields - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_ADD_ROW_BUTTON).click(); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_TOPIC_INPUT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_CONDITION_INPUT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_WHEN_INPUT); - cy.getBySel(getSpecificSelectorId(SETTINGS_OUTPUTS_KAFKA.TOPICS_TOPIC_INPUT, 1)); - cy.getBySel(getSpecificSelectorId(SETTINGS_OUTPUTS_KAFKA.TOPICS_CONDITION_INPUT, 1)); - cy.getBySel(getSpecificSelectorId(SETTINGS_OUTPUTS_KAFKA.TOPICS_WHEN_INPUT, 1)); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_DRAG_HANDLE_ICON); - - // Verify remove topic processors - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_REMOVE_ROW_BUTTON).click(); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_REMOVE_ROW_BUTTON).click(); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_TOPIC_INPUT).should('not.exist'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_CONDITION_INPUT).should('not.exist'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_WHEN_INPUT).should('not.exist'); - - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_PANEL).within(() => { - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_KEY_INPUT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_VALUE_INPUT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_ADD_ROW_BUTTON).should('be.disabled'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_REMOVE_ROW_BUTTON).should('be.disabled'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_CLIENT_ID_INPUT); - }); + // Verify Hash fields + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_HASH_OPTION).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_HASH_INPUT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_RANDOM_OPTION).click(); - // Verify add header - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_KEY_INPUT).type('key'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_VALUE_INPUT).type('value'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_ADD_ROW_BUTTON).should('be.enabled'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_REMOVE_ROW_BUTTON).should('be.disabled'); + // Topics + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_PANEL).within(() => { + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_DEFAULT_TOPIC_INPUT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_ADD_ROW_BUTTON); + }); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_ADD_ROW_BUTTON).click(); - cy.getBySel(getSpecificSelectorId(SETTINGS_OUTPUTS_KAFKA.HEADERS_KEY_INPUT, 1)); - cy.getBySel(getSpecificSelectorId(SETTINGS_OUTPUTS_KAFKA.HEADERS_VALUE_INPUT, 1)); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_ADD_ROW_BUTTON).should('be.enabled'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_REMOVE_ROW_BUTTON).should('be.enabled'); - - // Verify remove header - cy.getBySel( - getSpecificSelectorId(SETTINGS_OUTPUTS_KAFKA.HEADERS_REMOVE_ROW_BUTTON, 1) - ).click(); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_ADD_ROW_BUTTON).should('be.enabled'); + // Verify one topic processor fields + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_ADD_ROW_BUTTON).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_TOPIC_INPUT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_CONDITION_INPUT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_WHEN_INPUT); + + // Verify additional topic processor fields + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_ADD_ROW_BUTTON).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_TOPIC_INPUT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_CONDITION_INPUT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_WHEN_INPUT); + cy.getBySel(getSpecificSelectorId(SETTINGS_OUTPUTS_KAFKA.TOPICS_TOPIC_INPUT, 1)); + cy.getBySel(getSpecificSelectorId(SETTINGS_OUTPUTS_KAFKA.TOPICS_CONDITION_INPUT, 1)); + cy.getBySel(getSpecificSelectorId(SETTINGS_OUTPUTS_KAFKA.TOPICS_WHEN_INPUT, 1)); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_DRAG_HANDLE_ICON); + + // Verify remove topic processors + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_REMOVE_ROW_BUTTON).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_REMOVE_ROW_BUTTON).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_TOPIC_INPUT).should('not.exist'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_CONDITION_INPUT).should('not.exist'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_WHEN_INPUT).should('not.exist'); + + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_PANEL).within(() => { + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_KEY_INPUT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_VALUE_INPUT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_ADD_ROW_BUTTON).should('be.disabled'); cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_REMOVE_ROW_BUTTON).should('be.disabled'); - - // Compression - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.COMPRESSION_CODEC_INPUT).should('not.exist'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.COMPRESSION_SWITCH).click(); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.COMPRESSION_LEVEL_INPUT).should('not.exist'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.COMPRESSION_CODEC_INPUT).select('gzip'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.COMPRESSION_LEVEL_INPUT).should('exist'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.COMPRESSION_LEVEL_INPUT).select('1'); - - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.BROKER_PANEL).within(() => { - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.BROKER_ACK_RELIABILITY_SELECT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.BROKER_CHANNEL_BUFFER_SIZE_SELECT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.BROKER_TIMEOUT_SELECT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.BROKER_REACHABILITY_TIMEOUT_SELECT); - }); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.KEY_INPUT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_CLIENT_ID_INPUT).should( + 'have.value', + 'Elastic' + ); }); - it('displays proper error messages', () => { - selectKafkaOutput(); - cy.getBySel(SETTINGS_SAVE_BTN).click(); - - cy.contains('Name is required'); - cy.contains('URL is required'); - cy.contains('Username is required'); - cy.contains('Password is required'); - cy.contains('Default topic is required'); - shouldDisplayError(SETTINGS_OUTPUTS.NAME_INPUT); - shouldDisplayError(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_INPUT); - shouldDisplayError(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_PASSWORD_INPUT); - shouldDisplayError(SETTINGS_OUTPUTS_KAFKA.TOPICS_DEFAULT_TOPIC_INPUT); + // Verify add header + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_KEY_INPUT).type('key'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_VALUE_INPUT).type('value'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_ADD_ROW_BUTTON).should('be.enabled'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_REMOVE_ROW_BUTTON).should('be.disabled'); + + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_ADD_ROW_BUTTON).click(); + cy.getBySel(getSpecificSelectorId(SETTINGS_OUTPUTS_KAFKA.HEADERS_KEY_INPUT, 1)); + cy.getBySel(getSpecificSelectorId(SETTINGS_OUTPUTS_KAFKA.HEADERS_VALUE_INPUT, 1)); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_ADD_ROW_BUTTON).should('be.enabled'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_REMOVE_ROW_BUTTON).should('be.enabled'); + + // Verify remove header + cy.getBySel( + getSpecificSelectorId(SETTINGS_OUTPUTS_KAFKA.HEADERS_REMOVE_ROW_BUTTON, 1) + ).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_ADD_ROW_BUTTON).should('be.enabled'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_REMOVE_ROW_BUTTON).should('be.disabled'); + + // Compression + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.COMPRESSION_CODEC_INPUT).should('not.exist'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.COMPRESSION_SWITCH).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.COMPRESSION_LEVEL_INPUT).should('not.exist'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.COMPRESSION_CODEC_INPUT).select('gzip'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.COMPRESSION_LEVEL_INPUT).should('exist'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.COMPRESSION_LEVEL_INPUT).select('1'); + + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.BROKER_PANEL).within(() => { + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.BROKER_ACK_RELIABILITY_SELECT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.BROKER_TIMEOUT_SELECT); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.BROKER_REACHABILITY_TIMEOUT_SELECT); }); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.KEY_INPUT); }); - // Test buttons presence before accessing output directly via url and delete via api - describe('Output operations', () => { - let kafkaOutputId: string; + it('displays proper error messages', () => { + selectKafkaOutput(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.HEADERS_CLIENT_ID_INPUT).clear(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_ADD_ROW_BUTTON).click(); + cy.getBySel(SETTINGS_SAVE_BTN).click(); + + cy.contains('Name is required'); + cy.contains('Host is required'); + cy.contains('Username is required'); + cy.contains('Password is required'); + cy.contains('Default topic is required'); + cy.contains('Topic is required'); + cy.contains( + 'Client ID is invalid. Only letters, numbers, dots, underscores, and dashes are allowed.' + ); + cy.contains('Must be a key, value pair i.e. "http.response.code: 200"'); + shouldDisplayError(SETTINGS_OUTPUTS.NAME_INPUT); + shouldDisplayError(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_INPUT); + shouldDisplayError(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_PASSWORD_INPUT); + shouldDisplayError(SETTINGS_OUTPUTS_KAFKA.TOPICS_DEFAULT_TOPIC_INPUT); + shouldDisplayError(SETTINGS_OUTPUTS_KAFKA.TOPICS_CONDITION_INPUT); + shouldDisplayError(SETTINGS_OUTPUTS_KAFKA.TOPICS_TOPIC_INPUT); + shouldDisplayError(SETTINGS_OUTPUTS_KAFKA.HEADERS_CLIENT_ID_INPUT); + }); + }); - before(() => { - loadKafkaOutput().then((data) => { - kafkaOutputId = data.item.id; - }); - }); + // Test buttons presence before accessing output directly via url and delete via api + describe('Output operations', () => { + let kafkaOutputId: string; - it('opens edit modal', () => { - visit('/app/fleet/settings'); - cy.get(`a[href="/app/fleet/settings/outputs/${kafkaOutputId}"]`) - .parents('tr') - .within(() => { - cy.contains(kafkaOutputBody.name); - cy.contains(kafkaOutputBody.type); - cy.contains(kafkaOutputBody.hosts[0]); - cy.getBySel('editOutputBtn').click(); - cy.url().should('include', `/app/fleet/settings/outputs/${kafkaOutputId}`); - }); - }); - it('delete output', () => { - visit('/app/fleet/settings'); - cy.get(`a[href="/app/fleet/settings/outputs/${kafkaOutputId}"]`) - .parents('tr') - .within(() => { - cy.get('[title="Delete"]').click(); - }); - cy.getBySel(SETTINGS_CONFIRM_MODAL_BTN).click(); - cy.get(`a[href="app/fleet/settings/outputs/${kafkaOutputId}"]`).should('not.exist'); + before(() => { + loadKafkaOutput().then((data) => { + kafkaOutputId = data.item.id; }); }); - describe('Form submit', () => { - let kafkaOutputId: string; - - before(() => { - interceptOutputId((id) => { - kafkaOutputId = id; + it('opens edit modal', () => { + visit('/app/fleet/settings'); + cy.get(`a[href="/app/fleet/settings/outputs/${kafkaOutputId}"]`) + .parents('tr') + .within(() => { + cy.contains(kafkaOutputBody.name); + cy.contains(kafkaOutputBody.type); + cy.contains(kafkaOutputBody.hosts[0]); + cy.getBySel('editOutputBtn').click(); + cy.url().should('include', `/app/fleet/settings/outputs/${kafkaOutputId}`); }); - }); + }); + it('delete output', () => { + visit('/app/fleet/settings'); + cy.get(`a[href="/app/fleet/settings/outputs/${kafkaOutputId}"]`) + .parents('tr') + .within(() => { + cy.get('[title="Delete"]').click(); + }); + cy.getBySel(SETTINGS_CONFIRM_MODAL_BTN).click(); + cy.get(`a[href="app/fleet/settings/outputs/${kafkaOutputId}"]`).should('not.exist'); + }); + }); - after(() => { - cleanupOutput(kafkaOutputId); + describe('Form submit', () => { + let kafkaOutputId: string; + + before(() => { + interceptOutputId((id) => { + kafkaOutputId = id; }); + }); - it('saves the output', () => { - selectKafkaOutput(); + after(() => { + cleanupOutput(kafkaOutputId); + }); - fillInKafkaOutputForm(); + it('saves the output', () => { + selectKafkaOutput(); - cy.intercept('POST', '**/api/fleet/outputs').as('saveOutput'); + fillInKafkaOutputForm(); - cy.getBySel(SETTINGS_SAVE_BTN).click(); + cy.intercept('POST', '**/api/fleet/outputs').as('saveOutput'); - cy.wait('@saveOutput').then((interception) => { - const responseBody = interception.response?.body; - cy.visit(`/app/fleet/settings/outputs/${responseBody?.item?.id}`); - }); + cy.getBySel(SETTINGS_SAVE_BTN).click(); - validateSavedKafkaOutputForm(); + cy.wait('@saveOutput').then((interception) => { + const responseBody = interception.response?.body; + cy.visit(`/app/fleet/settings/outputs/${responseBody?.item?.id}`); }); + + validateSavedKafkaOutputForm(); }); + }); - describe('Form edit', () => { - let kafkaOutputId: string; + describe('Form edit', () => { + let kafkaOutputId: string; - before(() => { - loadKafkaOutput().then((data) => { - kafkaOutputId = data.item.id; - }); - }); - after(() => { - cleanupOutput(kafkaOutputId); + before(() => { + loadKafkaOutput().then((data) => { + kafkaOutputId = data.item.id; }); + }); + after(() => { + cleanupOutput(kafkaOutputId); + }); - it('edits the output', () => { - visit(`/app/fleet/settings/outputs/${kafkaOutputId}`); + it('edits the output', () => { + visit(`/app/fleet/settings/outputs/${kafkaOutputId}`); - resetKafkaOutputForm(); + resetKafkaOutputForm(); - fillInKafkaOutputForm(); + fillInKafkaOutputForm(); - cy.getBySel(SETTINGS_SAVE_BTN).click(); - cy.getBySel(SETTINGS_CONFIRM_MODAL_BTN).click(); - visit(`/app/fleet/settings/outputs/${kafkaOutputId}`); + cy.getBySel(SETTINGS_SAVE_BTN).click(); + cy.getBySel(SETTINGS_CONFIRM_MODAL_BTN).click(); + visit(`/app/fleet/settings/outputs/${kafkaOutputId}`); - validateSavedKafkaOutputForm(); - }); + validateSavedKafkaOutputForm(); }); + }); - describe('Form output type change', () => { - let kafkaOutputToESId: string; - let kafkaOutputToLogstashId: string; - let logstashOutputToKafkaId: string; - let esOutputToKafkaId: string; + describe('Form output type change', () => { + let kafkaOutputToESId: string; + let kafkaOutputToLogstashId: string; + let logstashOutputToKafkaId: string; + let esOutputToKafkaId: string; - before(() => { - loadKafkaOutput().then((data) => { - kafkaOutputToESId = data.item.id; - }); - loadKafkaOutput().then((data) => { - kafkaOutputToLogstashId = data.item.id; - }); - loadESOutput().then((data) => { - esOutputToKafkaId = data.item.id; - }); - loadLogstashOutput().then((data) => { - logstashOutputToKafkaId = data.item.id; - }); + before(() => { + loadKafkaOutput().then((data) => { + kafkaOutputToESId = data.item.id; }); - after(() => { - cleanupOutput(kafkaOutputToESId); - cleanupOutput(kafkaOutputToLogstashId); - cleanupOutput(logstashOutputToKafkaId); - cleanupOutput(esOutputToKafkaId); + loadKafkaOutput().then((data) => { + kafkaOutputToLogstashId = data.item.id; }); - it('changes output type from es to kafka', () => { - validateOutputTypeChangeToKafka(esOutputToKafkaId); + loadESOutput().then((data) => { + esOutputToKafkaId = data.item.id; }); - - it('changes output type from logstash to kafka', () => { - validateOutputTypeChangeToKafka(logstashOutputToKafkaId); + loadLogstashOutput().then((data) => { + logstashOutputToKafkaId = data.item.id; }); + }); + after(() => { + cleanupOutput(kafkaOutputToESId); + cleanupOutput(kafkaOutputToLogstashId); + cleanupOutput(logstashOutputToKafkaId); + cleanupOutput(esOutputToKafkaId); + }); + it('changes output type from es to kafka', () => { + validateOutputTypeChangeToKafka(esOutputToKafkaId); + }); - it('changes output type from kafka to es', () => { - visit(`/app/fleet/settings/outputs/${kafkaOutputToESId}`); - cy.getBySel(SETTINGS_OUTPUTS.TYPE_INPUT).select('elasticsearch'); - cy.getBySel(kafkaOutputFormValues.name.selector).clear().type('kafka_to_es'); + it('changes output type from logstash to kafka', () => { + validateOutputTypeChangeToKafka(logstashOutputToKafkaId); + }); - cy.intercept('PUT', '**/api/fleet/outputs/**').as('saveOutput'); + it('changes output type from kafka to es', () => { + visit(`/app/fleet/settings/outputs/${kafkaOutputToESId}`); + cy.getBySel(SETTINGS_OUTPUTS.TYPE_INPUT).select('elasticsearch'); + cy.getBySel(kafkaOutputFormValues.name.selector).clear().type('kafka_to_es'); + cy.get('[placeholder="Specify host URL"').clear().type('https://localhost:5000'); - cy.getBySel(SETTINGS_SAVE_BTN).click(); - cy.getBySel(SETTINGS_CONFIRM_MODAL_BTN).click(); + cy.intercept('PUT', '**/api/fleet/outputs/**').as('saveOutput'); - // wait for the save request to finish to avoid race condition - cy.wait('@saveOutput').then(() => { - visit(`/app/fleet/settings/outputs/${kafkaOutputToESId}`); - }); + cy.getBySel(SETTINGS_SAVE_BTN).click(); + cy.getBySel(SETTINGS_CONFIRM_MODAL_BTN).click(); - cy.getBySel(SETTINGS_OUTPUTS.TYPE_INPUT).should('have.value', 'elasticsearch'); - cy.getBySel(kafkaOutputFormValues.name.selector).should('have.value', 'kafka_to_es'); + // wait for the save request to finish to avoid race condition + cy.wait('@saveOutput').then(() => { + visit(`/app/fleet/settings/outputs/${kafkaOutputToESId}`); }); - it('changes output type from kafka to logstash', () => { - visit(`/app/fleet/settings/outputs/${kafkaOutputToLogstashId}`); - cy.getBySel(SETTINGS_OUTPUTS.TYPE_INPUT).select('logstash'); - cy.getBySel(kafkaOutputFormValues.name.selector).clear().type('kafka_to_logstash'); - cy.get('[placeholder="Specify host"').clear().type('localhost:5000'); - cy.get('[placeholder="Specify ssl certificate"]').clear().type('SSL CERTIFICATE'); - cy.get('[placeholder="Specify certificate key"]').clear().type('SSL KEY'); + cy.getBySel(SETTINGS_OUTPUTS.TYPE_INPUT).should('have.value', 'elasticsearch'); + cy.getBySel(kafkaOutputFormValues.name.selector).should('have.value', 'kafka_to_es'); + }); - cy.intercept('PUT', '**/api/fleet/outputs/**').as('saveOutput'); + it('changes output type from kafka to logstash', () => { + visit(`/app/fleet/settings/outputs/${kafkaOutputToLogstashId}`); + cy.getBySel(SETTINGS_OUTPUTS.TYPE_INPUT).select('logstash'); + cy.getBySel(kafkaOutputFormValues.name.selector).clear().type('kafka_to_logstash'); + cy.get('[placeholder="Specify host"').clear().type('localhost:5000'); + cy.get('[placeholder="Specify ssl certificate"]').clear().type('SSL CERTIFICATE'); + cy.get('[placeholder="Specify certificate key"]').clear().type('SSL KEY'); - cy.getBySel(SETTINGS_SAVE_BTN).click(); - cy.getBySel(SETTINGS_CONFIRM_MODAL_BTN).click(); + cy.intercept('PUT', '**/api/fleet/outputs/**').as('saveOutput'); - // wait for the save request to finish to avoid race condition - cy.wait('@saveOutput').then(() => { - visit(`/app/fleet/settings/outputs/${kafkaOutputToLogstashId}`); - }); + cy.getBySel(SETTINGS_SAVE_BTN).click(); + cy.getBySel(SETTINGS_CONFIRM_MODAL_BTN).click(); - cy.getBySel(SETTINGS_OUTPUTS.TYPE_INPUT).should('have.value', 'logstash'); - cy.getBySel(kafkaOutputFormValues.name.selector).should( - 'have.value', - 'kafka_to_logstash' - ); + // wait for the save request to finish to avoid race condition + cy.wait('@saveOutput').then(() => { + visit(`/app/fleet/settings/outputs/${kafkaOutputToLogstashId}`); }); + + cy.getBySel(SETTINGS_OUTPUTS.TYPE_INPUT).should('have.value', 'logstash'); + cy.getBySel(kafkaOutputFormValues.name.selector).should('have.value', 'kafka_to_logstash'); }); - } + }); }); }); diff --git a/x-pack/plugins/fleet/cypress/screens/fleet.ts b/x-pack/plugins/fleet/cypress/screens/fleet.ts index b21dfa7c4e66c..e6b6ac1f47008 100644 --- a/x-pack/plugins/fleet/cypress/screens/fleet.ts +++ b/x-pack/plugins/fleet/cypress/screens/fleet.ts @@ -136,11 +136,16 @@ export const getSpecificSelectorId = (selector: string, id: number) => { export const SETTINGS_OUTPUTS_KAFKA = { VERSION_SELECT: 'settingsOutputsFlyout.kafkaVersionInput', AUTHENTICATION_SELECT: 'settingsOutputsFlyout.kafkaAuthenticationRadioInput', + AUTHENTICATION_NONE_OPTION: 'kafkaAuthenticationNoneRadioButton', AUTHENTICATION_USERNAME_PASSWORD_OPTION: 'kafkaAuthenticationUsernamePasswordRadioButton', AUTHENTICATION_SSL_OPTION: 'kafkaAuthenticationSSLRadioButton', AUTHENTICATION_KERBEROS_OPTION: 'kafkaAuthenticationKerberosRadioButton', AUTHENTICATION_USERNAME_INPUT: 'settingsOutputsFlyout.kafkaUsernameInput', AUTHENTICATION_PASSWORD_INPUT: 'settingsOutputsFlyout.kafkaPasswordInput', + AUTHENTICATION_VERIFICATION_MODE_INPUT: 'settingsOutputsFlyout.kafkaVerificationModeInput', + AUTHENTICATION_CONNECTION_TYPE_SELECT: 'settingsOutputsFlyout.kafkaConnectionTypeRadioInput', + AUTHENTICATION_CONNECTION_TYPE_PLAIN_OPTION: 'kafkaConnectionTypePlaintextRadioButton', + AUTHENTICATION_CONNECTION_TYPE_ENCRYPTION_OPTION: 'kafkaConnectionTypeEncryptionRadioButton', AUTHENTICATION_SASL_SELECT: 'settingsOutputsFlyout.kafkaSaslInput', AUTHENTICATION_SASL_PLAIN_OPTION: 'kafkaSaslPlainRadioButton', AUTHENTICATION_SASL_SCRAM_256_OPTION: 'kafkaSaslScramSha256RadioButton', @@ -173,7 +178,6 @@ export const SETTINGS_OUTPUTS_KAFKA = { BROKER_PANEL: 'settingsOutputsFlyout.kafkaBrokerSettingsPanel', BROKER_TIMEOUT_SELECT: 'settingsOutputsFlyout.kafkaBrokerTimeoutInput', BROKER_REACHABILITY_TIMEOUT_SELECT: 'settingsOutputsFlyout.kafkaBrokerReachabilityTimeoutInput', - BROKER_CHANNEL_BUFFER_SIZE_SELECT: 'settingsOutputsFlyout.kafkaBrokerChannelBufferSizeInput', BROKER_ACK_RELIABILITY_SELECT: 'settingsOutputsFlyout.kafkaBrokerAckReliabilityInputLabel', KEY_INPUT: 'settingsOutputsFlyout.kafkaKeyInput', }; diff --git a/x-pack/plugins/fleet/cypress/screens/fleet_outputs.ts b/x-pack/plugins/fleet/cypress/screens/fleet_outputs.ts index c5f7a852197c1..de6ef1097b74a 100644 --- a/x-pack/plugins/fleet/cypress/screens/fleet_outputs.ts +++ b/x-pack/plugins/fleet/cypress/screens/fleet_outputs.ts @@ -21,6 +21,7 @@ export const selectKafkaOutput = () => { visit('/app/fleet/settings'); cy.getBySel(SETTINGS_OUTPUTS.ADD_BTN).click(); cy.getBySel(SETTINGS_OUTPUTS.TYPE_INPUT).select('kafka'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_PASSWORD_OPTION).click(); }; export const shouldDisplayError = (handler: string) => { @@ -56,7 +57,7 @@ export const kafkaOutputBody = { name: 'kafka_test1', type: 'kafka', is_default: false, - hosts: ['https://example.com'], + hosts: ['example.com:2000'], topics: [{ topic: 'test' }], auth_type: 'user_pass', username: 'kafka', @@ -96,6 +97,10 @@ export const kafkaOutputFormValues = { selector: SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_PASSWORD_INPUT, value: 'test_password', }, + verificationMode: { + selector: SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_VERIFICATION_MODE_INPUT, + value: 'certificate', + }, hash: { selector: SETTINGS_OUTPUTS_KAFKA.PARTITIONING_HASH_INPUT, value: 'testHash', @@ -110,7 +115,7 @@ export const kafkaOutputFormValues = { }, firstTopicCondition: { selector: SETTINGS_OUTPUTS_KAFKA.TOPICS_CONDITION_INPUT, - value: 'testCondition', + value: 'testCondition: abc', }, firstTopicWhen: { selector: SETTINGS_OUTPUTS_KAFKA.TOPICS_WHEN_INPUT, @@ -122,7 +127,7 @@ export const kafkaOutputFormValues = { }, secondTopicCondition: { selector: getSpecificSelectorId(SETTINGS_OUTPUTS_KAFKA.TOPICS_CONDITION_INPUT, 1), - value: 'testCondition1', + value: 'testCondition1: dca', }, secondTopicWhen: { selector: getSpecificSelectorId(SETTINGS_OUTPUTS_KAFKA.TOPICS_WHEN_INPUT, 1), @@ -154,11 +159,7 @@ export const kafkaOutputFormValues = { }, brokerAckReliability: { selector: SETTINGS_OUTPUTS_KAFKA.BROKER_ACK_RELIABILITY_SELECT, - value: 'Do not wait', - }, - brokerChannelBufferSize: { - selector: SETTINGS_OUTPUTS_KAFKA.BROKER_CHANNEL_BUFFER_SIZE_SELECT, - value: '512', + value: '0', }, brokerTimeout: { selector: SETTINGS_OUTPUTS_KAFKA.BROKER_TIMEOUT_SELECT, @@ -185,9 +186,13 @@ export const resetKafkaOutputForm = () => { export const fillInKafkaOutputForm = () => { cy.getBySel(kafkaOutputFormValues.name.selector).type(kafkaOutputFormValues.name.value); - cy.get('[placeholder="Specify host"').clear().type('http://localhost:5000'); + cy.get('[placeholder="Specify host"').clear().type('localhost:5000'); cy.getBySel(kafkaOutputFormValues.username.selector).type(kafkaOutputFormValues.username.value); cy.getBySel(kafkaOutputFormValues.password.selector).type(kafkaOutputFormValues.password.value); + cy.getBySel(kafkaOutputFormValues.verificationMode.selector).select( + kafkaOutputFormValues.verificationMode.value + ); + cy.get('[placeholder="Specify certificate authority"]').clear().type('testCA'); cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SASL_SCRAM_256_OPTION).click(); cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_HASH_OPTION).click(); @@ -249,9 +254,6 @@ export const fillInKafkaOutputForm = () => { cy.getBySel(kafkaOutputFormValues.brokerAckReliability.selector).select( kafkaOutputFormValues.brokerAckReliability.value ); - cy.getBySel(kafkaOutputFormValues.brokerChannelBufferSize.selector).select( - kafkaOutputFormValues.brokerChannelBufferSize.value - ); cy.getBySel(kafkaOutputFormValues.brokerTimeout.selector).select( kafkaOutputFormValues.brokerTimeout.value ); @@ -267,6 +269,9 @@ export const validateSavedKafkaOutputForm = () => { cy.getBySel(selector).should('have.value', value); }); + cy.get('[placeholder="Specify host"').should('have.value', 'localhost:5000'); + cy.get('[placeholder="Specify certificate authority"]').should('have.value', 'testCA'); + cy.getBySel(SETTINGS_OUTPUTS.TYPE_INPUT).should('have.value', 'kafka'); cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SASL_SCRAM_256_OPTION) @@ -285,6 +290,8 @@ export const validateOutputTypeChangeToKafka = (outputId: string) => { visit(`/app/fleet/settings/outputs/${outputId}`); cy.getBySel(kafkaOutputFormValues.name.selector).clear(); cy.getBySel(SETTINGS_OUTPUTS.TYPE_INPUT).select('kafka'); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_PASSWORD_OPTION).click(); + fillInKafkaOutputForm(); cy.intercept('PUT', '**/api/fleet/outputs/**').as('saveOutput'); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.test.tsx index d577a1643ac0c..46b367011395c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.test.tsx @@ -43,9 +43,6 @@ const logstashInputsLabels = [ ]; const kafkaInputsLabels = [ - 'Username', - 'Password', - 'SASL Mechanism', 'Partitioning strategy', 'Number of events', 'Default topic', @@ -53,7 +50,6 @@ const kafkaInputsLabels = [ 'Value', 'Broker timeout', 'Broker reachability timeout', - 'Channel buffer size', 'ACK Reliability', 'Key (optional)', ]; @@ -143,7 +139,7 @@ describe('EditOutputFlyout', () => { }); // Does not show logstash inputs - logstashInputsLabels.forEach((label) => { + ['Client SSL certificate key', 'Client SSL certificate'].forEach((label) => { expect(utils.queryByLabelText(label)).toBeNull(); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka.tsx index 222def40b5a75..f6af3270487be 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka.tsx @@ -84,13 +84,13 @@ export const OutputFormKafkaSection: React.FunctionComponent = (props) => helpText={ ), @@ -105,6 +105,7 @@ export const OutputFormKafkaSection: React.FunctionComponent = (props) => + diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_authentication.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_authentication.tsx index 271f3fe144aca..42a7b66727597 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_authentication.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_authentication.tsx @@ -5,14 +5,16 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { + EuiFieldPassword, EuiFieldText, EuiFormRow, EuiPanel, EuiRadioGroup, + EuiSelect, EuiSpacer, EuiTextArea, EuiTitle, @@ -20,7 +22,13 @@ import { import { FormattedMessage } from '@kbn/i18n-react'; import { MultiRowInput } from '../multi_row_input'; -import { kafkaAuthType, kafkaSaslMechanism } from '../../../../../../../common/constants'; + +import { + kafkaAuthType, + kafkaConnectionType, + kafkaSaslMechanism, + kafkaVerificationModes, +} from '../../../../../../../common/constants'; import type { OutputFormInputsType } from './use_output_form'; @@ -43,6 +51,11 @@ const kafkaSaslOptions = [ ]; const kafkaAuthenticationsOptions = [ + { + id: kafkaAuthType.None, + label: 'None', + 'data-test-subj': 'kafkaAuthenticationNoneRadioButton', + }, { id: kafkaAuthType.Userpass, label: 'Username / Password', @@ -53,11 +66,6 @@ const kafkaAuthenticationsOptions = [ label: 'SSL', 'data-test-subj': 'kafkaAuthenticationSSLRadioButton', }, - { - id: kafkaAuthType.Kerberos, - label: 'Kerberos', - 'data-test-subj': 'kafkaAuthenticationKerberosRadioButton', - }, ]; export const OutputFormKafkaAuthentication: React.FunctionComponent<{ @@ -65,28 +73,56 @@ export const OutputFormKafkaAuthentication: React.FunctionComponent<{ }> = (props) => { const { inputs } = props; + const kafkaVerificationModeOptions = useMemo( + () => + (Object.keys(kafkaVerificationModes) as Array).map( + (key) => { + return { + text: kafkaVerificationModes[key], + label: key, + }; + } + ), + [] + ); + + const kafkaConnectionTypeOptions = useMemo( + () => + (Object.keys(kafkaConnectionType) as Array).map((key) => { + return { + id: kafkaConnectionType[key], + label: key, + 'data-test-subj': `kafkaConnectionType${key}RadioButton`, + }; + }), + [] + ); + const renderAuthentication = () => { switch (inputs.kafkaAuthMethodInput.value) { + case kafkaAuthType.None: + return ( + + } + > + + + ); case kafkaAuthType.Ssl: return ( <> - ); - case kafkaAuthType.Kerberos: - return null; default: case kafkaAuthType.Userpass: return ( @@ -165,7 +199,8 @@ export const OutputFormKafkaAuthentication: React.FunctionComponent<{ } {...inputs.kafkaAuthPasswordInput.formRowProps} > - { + const displayEncryptionSection = + inputs.kafkaConnectionTypeInput.value !== kafkaConnectionType.Plaintext || + inputs.kafkaAuthMethodInput.value !== kafkaAuthType.None; + + if (!displayEncryptionSection) { + return null; + } + + return ( + <> + + + + + + } + > + + + + ); + }; + return ( - - -

    - + + +

    + +

    +
    + + + -

    -
    - - - - - {renderAuthentication()} -
    +
    + {renderAuthentication()} +
    + {renderEncryptionSection()} + ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_broker.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_broker.tsx index f6b0477c81515..2fb40f3e5e376 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_broker.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_broker.tsx @@ -27,14 +27,18 @@ export const OutputFormKafkaBroker: React.FunctionComponent<{ inputs: OutputForm [] ); - const kafkaBrokerChannelBufferSizeOptions = useMemo( - () => - Array.from({ length: 4 }, (_, i) => Math.pow(2, i + 7)).map((buffer) => ({ - text: buffer, - label: `${buffer}`, - })), - [] - ); + const getAckReliabilityLabel = (value: number) => { + switch (value) { + case kafkaAcknowledgeReliabilityLevel.DoNotWait: + return 'No response'; + case kafkaAcknowledgeReliabilityLevel.Replica: + return 'Wait for all replicas to commit'; + default: + case kafkaAcknowledgeReliabilityLevel.Commit: + return 'Wait for local commit'; + } + }; + const kafkaBrokerAckReliabilityOptions = useMemo( () => ( @@ -44,7 +48,7 @@ export const OutputFormKafkaBroker: React.FunctionComponent<{ inputs: OutputForm ).map((key) => { return { text: kafkaAcknowledgeReliabilityLevel[key], - label: kafkaAcknowledgeReliabilityLevel[key], + label: getAckReliabilityLabel(kafkaAcknowledgeReliabilityLevel[key]), }; }), [] @@ -111,28 +115,6 @@ export const OutputFormKafkaBroker: React.FunctionComponent<{ inputs: OutputForm options={kafkaBrokerTimeoutOptions} /> - - } - helpText={ - - } - > - - } > diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_headers.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_headers.tsx index 3f605463a65bc..89ff4b5d0de7a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_headers.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_headers.tsx @@ -114,7 +114,7 @@ export const OutputFormKafkaHeaders: React.FunctionComponent<{ inputs: OutputFor const keyErrors = matchErrorsByIndex(index, 'key'); const valueErrors = matchErrorsByIndex(index, 'value'); return ( - <> +
    {index > 0 && } @@ -173,7 +173,7 @@ export const OutputFormKafkaHeaders: React.FunctionComponent<{ inputs: OutputFor /> - +
    ); })} {displayErrors(globalErrors)} @@ -198,6 +198,7 @@ export const OutputFormKafkaHeaders: React.FunctionComponent<{ inputs: OutputFor defaultMessage="Client ID" /> } + {...inputs.kafkaClientIdInput.formRowProps} > { @@ -64,7 +63,30 @@ export const OutputFormKafkaTopics: React.FunctionComponent<{ inputs: OutputForm acc[err.index] = []; } - acc[err.index].push(err.message); + if (!err.condition) { + acc[err.index].push(err.message); + } + + return acc; + }, []); + }, [errors]); + + const indexedConditionErrors = useMemo(() => { + if (!errors) { + return []; + } + return errors.reduce((acc, err) => { + if (err.index === undefined) { + return acc; + } + + if (!acc[err.index]) { + acc[err.index] = []; + } + + if (err.condition) { + acc[err.index].push(err.message); + } return acc; }, []); @@ -97,9 +119,10 @@ export const OutputFormKafkaTopics: React.FunctionComponent<{ inputs: OutputForm (index: number) => { const updatedTopics = topics.filter((_, i) => i !== index); indexedErrors.splice(index, 1); + indexedConditionErrors.splice(index, 1); onChange(updatedTopics); }, - [topics, indexedErrors, onChange] + [topics, indexedErrors, indexedConditionErrors, onChange] ); const displayErrors = (errorMessages?: string[]) => { @@ -132,10 +155,13 @@ export const OutputFormKafkaTopics: React.FunctionComponent<{ inputs: OutputForm const sourceErrors = indexedErrors[source.index]; indexedErrors.splice(source.index, 1); indexedErrors.splice(destination.index, 0, sourceErrors); + const sourceConditionErrors = indexedConditionErrors[source.index]; + indexedConditionErrors.splice(source.index, 1); + indexedConditionErrors.splice(destination.index, 0, sourceConditionErrors); onChange(items); } }, - [topics, indexedErrors, onChange] + [topics, indexedErrors, indexedConditionErrors, onChange] ); return ( @@ -187,6 +213,7 @@ export const OutputFormKafkaTopics: React.FunctionComponent<{ inputs: OutputForm {topics.map((topic, index) => { const topicErrors = indexedErrors[index]; + const topicConditionErrors = indexedConditionErrors[index]; return (
    - + 0} + > 0} onChange={(e) => handleTopicProcessorChange(index, 'condition', e.target.value) } @@ -301,6 +333,7 @@ export const OutputFormKafkaTopics: React.FunctionComponent<{ inputs: OutputForm <> {topics.map((topic, index) => { const topicErrors = indexedErrors[index]; + const topicConditionErrors = indexedConditionErrors[index]; return ( <> @@ -320,10 +353,15 @@ export const OutputFormKafkaTopics: React.FunctionComponent<{ inputs: OutputForm - + 0} + > 0} onChange={(e) => handleTopicProcessorChange(index, 'condition', e.target.value) } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.test.tsx index 04b07ac9c8b4a..d5da6f553cf89 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.test.tsx @@ -11,9 +11,71 @@ import { validateYamlConfig, validateCATrustedFingerPrint, validateKafkaHeaders, + validateKafkaHosts, } from './output_form_validators'; describe('Output form validation', () => { + describe('validateKafkaHosts', () => { + it('should not work without any urls', () => { + const res = validateKafkaHosts([]); + + expect(res).toEqual([{ message: 'Host is required' }]); + }); + + it('should work with valid url', () => { + const res = validateKafkaHosts(['test.fr:9200']); + + expect(res).toBeUndefined(); + }); + + it('should work with multiple valid urls', () => { + const res = validateKafkaHosts(['test.fr:9200', 'test2.fr:9200', 'test.fr:9999']); + + expect(res).toBeUndefined(); + }); + + it('should return an error with invalid url', () => { + const res = validateKafkaHosts(['toto']); + + expect(res).toEqual([ + { index: 0, message: 'Invalid format. Expected "host:port" without protocol.' }, + ]); + }); + + it('should return an error with url with defined protocol', () => { + const res = validateKafkaHosts(['https://test.fr:9200']); + + expect(res).toEqual([ + { index: 0, message: 'Invalid format. Expected "host:port" without protocol.' }, + ]); + }); + + it('should return an error with url with invalid port', () => { + const res = validateKafkaHosts(['test.fr:qwerty9200']); + + expect(res).toEqual([ + { index: 0, message: 'Invalid port number. Expected a number between 1 and 65535' }, + ]); + }); + + it('should return an error with multiple invalid urls', () => { + const res = validateKafkaHosts(['toto', 'tata']); + + expect(res).toEqual([ + { index: 0, message: 'Invalid format. Expected "host:port" without protocol.' }, + { index: 1, message: 'Invalid format. Expected "host:port" without protocol.' }, + ]); + }); + it('should return an error with duplicate urls', () => { + const res = validateKafkaHosts(['test.fr:2000', 'test.fr:2000']); + + expect(res).toEqual([ + { index: 0, message: 'Duplicate URL' }, + { index: 1, message: 'Duplicate URL' }, + ]); + }); + }); + describe('validateESHosts', () => { it('should not work without any urls', () => { const res = validateESHosts([]); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.tsx index 8d658e545a854..bbb5b5dda3e91 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_validators.tsx @@ -8,6 +8,73 @@ import { i18n } from '@kbn/i18n'; import { safeLoad } from 'js-yaml'; +export function validateKafkaHosts(value: string[]) { + const res: Array<{ message: string; index?: number }> = []; + const urlIndexes: { [key: string]: number[] } = {}; + + value.forEach((val, idx) => { + if (!val) { + res.push({ + message: i18n.translate('xpack.fleet.settings.outputForm.kafkaHostFieldRequiredError', { + defaultMessage: 'Host is required', + }), + }); + return; + } + + // Split the URL into parts based on ":" + const urlParts = val.split(':'); + if (urlParts.length !== 2 || !urlParts[0] || !urlParts[1]) { + res.push({ + message: i18n.translate('xpack.fleet.settings.outputForm.kafkaHostPortError', { + defaultMessage: 'Invalid format. Expected "host:port" without protocol.', + }), + index: idx, + }); + return; + } + + // Validate that the port is a valid number + const port = parseInt(urlParts[1], 10); + if (isNaN(port) || port < 1 || port > 65535) { + res.push({ + message: i18n.translate('xpack.fleet.settings.outputForm.kafkaPortError', { + defaultMessage: 'Invalid port number. Expected a number between 1 and 65535', + }), + index: idx, + }); + } + + const curIndexes = urlIndexes[val] || []; + urlIndexes[val] = [...curIndexes, idx]; + }); + + Object.values(urlIndexes) + .filter(({ length }) => length > 1) + .forEach((indexes) => { + indexes.forEach((index) => + res.push({ + message: i18n.translate('xpack.fleet.settings.outputForm.kafkaHostDuplicateError', { + defaultMessage: 'Duplicate URL', + }), + index, + }) + ); + }); + + if (value.length === 0) { + res.push({ + message: i18n.translate('xpack.fleet.settings.outputForm.kafkaHostRequiredError', { + defaultMessage: 'Host is required', + }), + }); + } + + if (res.length) { + return res; + } +} + export function validateESHosts(value: string[]) { const res: Array<{ message: string; index?: number }> = []; const urlIndexes: { [key: string]: number[] } = {}; @@ -211,14 +278,31 @@ export function validateKafkaDefaultTopic(value: string) { } } +export function validateKafkaClientId(value: string) { + const regex = /^[A-Za-z0-9._-]+$/; + return regex.test(value) + ? undefined + : [ + i18n.translate('xpack.fleet.settings.outputForm.kafkaClientIdFormattingMessage', { + defaultMessage: + 'Client ID is invalid. Only letters, numbers, dots, underscores, and dashes are allowed.', + }), + ]; +} + export function validateKafkaTopics( topics: Array<{ topic: string; + when?: { + condition?: string; + type?: string; + }; }> ) { const errors: Array<{ message: string; index: number; + condition?: boolean; }> = []; topics.forEach((topic, index) => { @@ -230,6 +314,19 @@ export function validateKafkaTopics( index, }); } + if ( + !topic.when?.condition || + topic.when.condition === '' || + topic.when.condition.split(':').length - 1 !== 1 + ) { + errors.push({ + message: i18n.translate('xpack.fleet.settings.outputForm.kafkaTopicConditionRequired', { + defaultMessage: 'Must be a key, value pair i.e. "http.response.code: 200"', + }), + index, + condition: true, + }); + } }); if (errors.length) { return errors; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx index dbd1b4b0c7a30..bd1891f3ebc12 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx @@ -21,8 +21,10 @@ import { kafkaAcknowledgeReliabilityLevel, kafkaAuthType, kafkaCompressionType, + kafkaConnectionType, kafkaPartitionType, kafkaSaslMechanism, + kafkaVerificationModes, outputType, } from '../../../../../../../common/constants'; @@ -57,6 +59,8 @@ import { validateKafkaHeaders, validateKafkaDefaultTopic, validateKafkaTopics, + validateKafkaClientId, + validateKafkaHosts, } from './output_form_validators'; import { confirmUpdate } from './confirm_update'; @@ -87,7 +91,9 @@ export interface OutputFormInputsType { maxBatchBytes: ReturnType; kafkaHostsInput: ReturnType; kafkaVersionInput: ReturnType; + kafkaVerificationModeInput: ReturnType; kafkaAuthMethodInput: ReturnType; + kafkaConnectionTypeInput: ReturnType; kafkaSaslMechanismInput: ReturnType; kafkaAuthUsernameInput: ReturnType; kafkaAuthPasswordInput: ReturnType; @@ -104,7 +110,6 @@ export interface OutputFormInputsType { kafkaCompressionCodecInput: ReturnType; kafkaBrokerTimeoutInput: ReturnType; kafkaBrokerReachabilityTimeoutInput: ReturnType; - kafkaBrokerChannelBufferSizeInput: ReturnType; kafkaBrokerAckReliabilityInput: ReturnType; kafkaKeyInput: ReturnType; kafkaSslCertificateInput: ReturnType; @@ -278,15 +283,20 @@ export function useOutputForm(onSucess: () => void, output?: Output) { const kafkaHostsInput = useComboInput( 'kafkaHostsComboBox', output?.hosts ?? [], - validateESHosts, + validateKafkaHosts, isDisabled('hosts') ); const kafkaAuthMethodInput = useRadioInput( - kafkaOutput?.auth_type ?? kafkaAuthType.Userpass, + kafkaOutput?.auth_type ?? kafkaAuthType.None, isDisabled('auth_type') ); + const kafkaConnectionTypeInput = useRadioInput( + kafkaOutput?.connection_type ?? kafkaConnectionType.Plaintext, + isDisabled('connection_type') + ); + const kafkaAuthUsernameInput = useInput( kafkaOutput?.username, kafkaAuthMethodInput.value === kafkaAuthType.Userpass ? validateKafkaUsername : undefined, @@ -315,6 +325,12 @@ export function useOutputForm(onSucess: () => void, output?: Output) { isSSLEditable ); + const kafkaVerificationModeInput = useInput( + kafkaOutput?.ssl?.verification_mode ?? kafkaVerificationModes.Full, + undefined, + isSSLEditable + ); + const kafkaSaslMechanismInput = useRadioInput( kafkaOutput?.sasl?.mechanism ?? kafkaSaslMechanism.Plain, isDisabled('sasl') @@ -360,8 +376,8 @@ export function useOutputForm(onSucess: () => void, output?: Output) { ); const kafkaClientIdInput = useInput( - kafkaOutput?.client_id ?? 'Elastic agent', - undefined, + kafkaOutput?.client_id ?? 'Elastic', + validateKafkaClientId, isDisabled('client_id') ); @@ -392,16 +408,10 @@ export function useOutputForm(onSucess: () => void, output?: Output) { isDisabled('timeout') ); - const kafkaBrokerChannelBufferSizeInput = useInput( - `${kafkaOutput?.broker_buffer_size ?? 256}`, - undefined, - isDisabled('broker_buffer_size') - ); - const kafkaBrokerAckReliabilityInput = useInput( - kafkaOutput?.broker_ack_reliability ?? kafkaAcknowledgeReliabilityLevel.Commit, + `${kafkaOutput?.required_acks ?? kafkaAcknowledgeReliabilityLevel.Commit}`, undefined, - isDisabled('broker_ack_reliability') + isDisabled('required_acks') ); const kafkaKeyInput = useInput(kafkaOutput?.key, undefined, isDisabled('key')); @@ -434,7 +444,9 @@ export function useOutputForm(onSucess: () => void, output?: Output) { maxBatchBytes, kafkaVersionInput, kafkaHostsInput, + kafkaVerificationModeInput, kafkaAuthMethodInput, + kafkaConnectionTypeInput, kafkaAuthUsernameInput, kafkaAuthPasswordInput, kafkaSaslMechanismInput, @@ -449,7 +461,6 @@ export function useOutputForm(onSucess: () => void, output?: Output) { kafkaCompressionCodecInput, kafkaBrokerTimeoutInput, kafkaBrokerReachabilityTimeoutInput, - kafkaBrokerChannelBufferSizeInput, kafkaBrokerAckReliabilityInput, kafkaKeyInput, kafkaSslCertificateAuthoritiesInput, @@ -467,6 +478,7 @@ export function useOutputForm(onSucess: () => void, output?: Output) { const kafkaHostsValid = kafkaHostsInput.validate(); const kafkaUsernameValid = kafkaAuthUsernameInput.validate(); const kafkaPasswordValid = kafkaAuthPasswordInput.validate(); + const kafkaClientIDValid = kafkaClientIdInput.validate(); const kafkaSslCertificateValid = kafkaSslCertificateInput.validate(); const kafkaSslKeyValid = kafkaSslKeyInput.validate(); const kafkaDefaultTopicValid = kafkaDefaultTopicInput.validate(); @@ -501,7 +513,8 @@ export function useOutputForm(onSucess: () => void, output?: Output) { kafkaHeadersValid && kafkaDefaultTopicValid && kafkaTopicsValid && - additionalYamlConfigValid + additionalYamlConfigValid && + kafkaClientIDValid ); } else { // validate ES @@ -519,6 +532,7 @@ export function useOutputForm(onSucess: () => void, output?: Output) { kafkaHostsInput, kafkaAuthUsernameInput, kafkaAuthPasswordInput, + kafkaClientIdInput, kafkaSslCertificateInput, kafkaSslKeyInput, kafkaDefaultTopicInput, @@ -582,7 +596,7 @@ export function useOutputForm(onSucess: () => void, output?: Output) { const payload: NewOutput = (() => { const parseIntegerIfStringDefined = (value: string | undefined): number | undefined => { if (value !== undefined) { - const parsedInt = parseInt(value, 10); // Specify the base as 10 for decimal numbers + const parsedInt = parseInt(value, 10); if (!isNaN(parsedInt)) { return parsedInt; } @@ -592,6 +606,10 @@ export function useOutputForm(onSucess: () => void, output?: Output) { switch (typeInput.value) { case outputType.Kafka: + const definedCA = kafkaSslCertificateAuthoritiesInput.value.filter( + (val) => val !== '' + ).length; + return { name: nameInput.value, type: outputType.Kafka, @@ -599,18 +617,26 @@ export function useOutputForm(onSucess: () => void, output?: Output) { is_default: defaultOutputInput.value, is_default_monitoring: defaultMonitoringOutputInput.value, config_yaml: additionalYamlConfigInput.value, - ...(kafkaAuthMethodInput.value === kafkaAuthType.Ssl + ...(kafkaConnectionTypeInput.value !== kafkaConnectionType.Plaintext || + kafkaAuthMethodInput.value !== kafkaAuthType.None ? { ssl: { - certificate: kafkaSslCertificateInput.value, - key: kafkaSslKeyInput.value, - certificate_authorities: kafkaSslCertificateAuthoritiesInput.value.filter( - (val) => val !== '' - ), + ...(definedCA + ? { + certificate_authorities: + kafkaSslCertificateAuthoritiesInput.value.filter((val) => val !== ''), + } + : {}), + ...(kafkaAuthMethodInput.value === kafkaAuthType.Ssl + ? { + certificate: kafkaSslCertificateInput.value, + key: kafkaSslKeyInput.value, + } + : {}), + verification_mode: kafkaVerificationModeInput.value, }, } : {}), - proxy_id: proxyIdValue, client_id: kafkaClientIdInput.value || undefined, @@ -626,8 +652,17 @@ export function useOutputForm(onSucess: () => void, output?: Output) { : {}), auth_type: kafkaAuthMethodInput.value, - ...(kafkaAuthUsernameInput.value ? { username: kafkaAuthUsernameInput.value } : {}), - ...(kafkaAuthPasswordInput.value ? { password: kafkaAuthPasswordInput.value } : {}), + ...(kafkaAuthMethodInput.value === kafkaAuthType.None + ? { connection_type: kafkaConnectionTypeInput.value } + : {}), + ...(kafkaAuthMethodInput.value === kafkaAuthType.Userpass && + kafkaAuthUsernameInput.value + ? { username: kafkaAuthUsernameInput.value } + : {}), + ...(kafkaAuthMethodInput.value === kafkaAuthType.Userpass && + kafkaAuthPasswordInput.value + ? { password: kafkaAuthPasswordInput.value } + : {}), ...(kafkaAuthMethodInput.value === kafkaAuthType.Userpass && kafkaSaslMechanismInput.value ? { sasl: { mechanism: kafkaSaslMechanismInput.value } } @@ -665,10 +700,7 @@ export function useOutputForm(onSucess: () => void, output?: Output) { broker_timeout: parseIntegerIfStringDefined( kafkaBrokerReachabilityTimeoutInput.value ), - broker_ack_reliability: kafkaBrokerAckReliabilityInput.value, - broker_buffer_size: parseIntegerIfStringDefined( - kafkaBrokerChannelBufferSizeInput.value - ), + required_acks: parseIntegerIfStringDefined(kafkaBrokerAckReliabilityInput.value), ...shipperParams, } as KafkaOutput; case outputType.Logstash: @@ -752,6 +784,7 @@ export function useOutputForm(onSucess: () => void, output?: Output) { compressionLevelInput.value, loadBalanceEnabledInput.value, typeInput.value, + kafkaSslCertificateAuthoritiesInput.value, nameInput.value, kafkaHostsInput.value, defaultOutputInput.value, @@ -760,12 +793,13 @@ export function useOutputForm(onSucess: () => void, output?: Output) { kafkaAuthMethodInput.value, kafkaSslCertificateInput.value, kafkaSslKeyInput.value, - kafkaSslCertificateAuthoritiesInput.value, + kafkaVerificationModeInput.value, kafkaClientIdInput.value, kafkaVersionInput.value, kafkaKeyInput.value, kafkaCompressionCodecInput.value, kafkaCompressionLevelInput.value, + kafkaConnectionTypeInput.value, kafkaAuthUsernameInput.value, kafkaAuthPasswordInput.value, kafkaSaslMechanismInput.value, @@ -779,7 +813,6 @@ export function useOutputForm(onSucess: () => void, output?: Output) { kafkaBrokerTimeoutInput.value, kafkaBrokerReachabilityTimeoutInput.value, kafkaBrokerAckReliabilityInput.value, - kafkaBrokerChannelBufferSizeInput.value, logstashHostsInput.value, sslCertificateInput.value, sslKeyInput.value, diff --git a/x-pack/plugins/fleet/public/hooks/use_input.ts b/x-pack/plugins/fleet/public/hooks/use_input.ts index a48e3075d7a42..dbc60eafda833 100644 --- a/x-pack/plugins/fleet/public/hooks/use_input.ts +++ b/x-pack/plugins/fleet/public/hooks/use_input.ts @@ -86,6 +86,16 @@ export function useInput( export function useRadioInput(defaultValue: string, disabled = false) { const [value, setValue] = useState(defaultValue); + const [hasChanged, setHasChanged] = useState(false); + + useEffect(() => { + if (hasChanged) { + return; + } + if (value !== defaultValue) { + setHasChanged(true); + } + }, [hasChanged, value, defaultValue]); const onChange = useCallback(setValue, [setValue]); @@ -97,6 +107,7 @@ export function useRadioInput(defaultValue: string, disabled = false) { }, setValue, value, + hasChanged, }; } @@ -137,11 +148,15 @@ export function useSwitchInput(defaultValue = false, disabled = false) { function useCustomInput( id: string, defaultValue: T, - validate?: (value: T) => Array<{ message: string; index?: number }> | undefined, + validate?: ( + value: T + ) => Array<{ message: string; index?: number; condition?: boolean }> | undefined, disabled = false ) { const [value, setValue] = useState(defaultValue); - const [errors, setErrors] = useState | undefined>(); + const [errors, setErrors] = useState< + Array<{ message: string; index?: number; condition?: boolean }> | undefined + >(); const [hasChanged, setHasChanged] = useState(false); useEffect(() => { @@ -237,7 +252,9 @@ type Topic = Array<{ export function useTopicsInput( id: string, defaultValue: Topic = [], - validate?: (value: Topic) => Array<{ message: string; index: number }> | undefined, + validate?: ( + value: Topic + ) => Array<{ message: string; index: number; condition?: boolean }> | undefined, disabled = false ) { return useCustomInput(id, defaultValue, validate, disabled); diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index 43e0069d3be48..b7013bf43ff84 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -25,6 +25,8 @@ import { UNINSTALL_TOKENS_SAVED_OBJECT_TYPE, } from '../constants'; +import { migrateOutputEvictionsFromV8100, migrateOutputToV8100 } from './migrations/to_v8_10_0'; + import { migrateSyntheticsPackagePolicyToV8100 } from './migrations/synthetics/to_v8_10_0'; import { migratePackagePolicyEvictionsFromV8100 } from './migrations/security_solution/to_v8_10_0'; @@ -177,6 +179,7 @@ const getSavedObjectTypes = (): { [key: string]: SavedObjectsType } => ({ compression_level: { type: 'integer' }, client_id: { type: 'keyword' }, auth_type: { type: 'keyword' }, + connection_type: { type: 'keyword' }, username: { type: 'keyword' }, password: { type: 'text', index: false }, sasl: { @@ -229,6 +232,29 @@ const getSavedObjectTypes = (): { [key: string]: SavedObjectsType } => ({ broker_timeout: { type: 'integer' }, broker_ack_reliability: { type: 'text' }, broker_buffer_size: { type: 'integer' }, + required_acks: { type: 'integer' }, + channel_buffer_size: { type: 'integer' }, + }, + }, + modelVersions: { + '1': { + changes: [ + { + type: 'mappings_deprecation', + deprecatedMappings: [ + 'broker_ack_reliability', + 'broker_buffer_size', + 'channel_buffer_size', + ], + }, + { + type: 'data_backfill', + backfillFn: migrateOutputToV8100, + }, + ], + schemas: { + forwardCompatibility: migrateOutputEvictionsFromV8100, + }, }, }, migrations: { @@ -528,6 +554,24 @@ export function registerEncryptedSavedObjects( 'config_yaml', 'is_preconfigured', 'proxy_id', + 'version', + 'key', + 'compression', + 'compression_level', + 'client_id', + 'auth_type', + 'connection_type', + 'username', + 'sasl', + 'partition', + 'random', + 'round_robin', + 'hash', + 'topics', + 'headers', + 'timeout', + 'broker_timeout', + 'required_acks', ]), }); // Encrypted saved objects diff --git a/x-pack/plugins/fleet/server/saved_objects/migrations/to_v8_10_0.test.ts b/x-pack/plugins/fleet/server/saved_objects/migrations/to_v8_10_0.test.ts new file mode 100644 index 0000000000000..92b8c2c2d34b6 --- /dev/null +++ b/x-pack/plugins/fleet/server/saved_objects/migrations/to_v8_10_0.test.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SavedObjectModelTransformationContext } from '@kbn/core-saved-objects-server'; + +import { + migrateOutputToV8100 as migration, + migrateOutputEvictionsFromV8100 as eviction, +} from './to_v8_10_0'; + +describe('8.10.0 migration', () => { + describe('Migrate output to v8.10.0', () => { + const outputDoc = (connectionType = {}) => ({ + id: 'mock-saved-object-id', + attributes: { + id: 'id', + name: 'Test', + type: 'kafka' as const, + is_default: false, + is_default_monitoring: false, + hosts: ['localhost:9092'], + ca_sha256: 'sha', + ca_trusted_fingerprint: 'fingerprint', + version: '7.10.0', + key: 'key', + compression: 'gzip' as const, + compression_level: 4, + client_id: 'Elastic', + auth_type: 'none' as const, + ...connectionType, + topics: [{ topic: 'topic' }], + }, + type: 'nested', + }); + + it('adds connection type field to output and sets it to plaintext', () => { + const initialDoc = outputDoc({}); + + const migratedDoc = outputDoc({ + connection_type: 'plaintext', + }); + + expect(migration(initialDoc, {} as SavedObjectModelTransformationContext)).toEqual({ + attributes: migratedDoc.attributes, + }); + }); + + it('removes connection type field from output', () => { + const initialDoc = outputDoc({ + connection_type: 'plaintext', + }); + + const migratedDoc = outputDoc({}); + + expect(eviction(initialDoc.attributes)).toEqual(migratedDoc.attributes); + }); + }); +}); diff --git a/x-pack/plugins/fleet/server/saved_objects/migrations/to_v8_10_0.ts b/x-pack/plugins/fleet/server/saved_objects/migrations/to_v8_10_0.ts new file mode 100644 index 0000000000000..fc0ebda76086b --- /dev/null +++ b/x-pack/plugins/fleet/server/saved_objects/migrations/to_v8_10_0.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { + SavedObjectModelDataBackfillFn, + SavedObjectUnsanitizedDoc, +} from '@kbn/core-saved-objects-server'; + +import type { SavedObjectModelVersionForwardCompatibilityFn } from '@kbn/core-saved-objects-server'; + +import { omit } from 'lodash'; + +import type { Output } from '../../../common'; + +export const migrateOutputToV8100: SavedObjectModelDataBackfillFn = (outputDoc) => { + const updatedOutputDoc: SavedObjectUnsanitizedDoc = outputDoc; + + if (updatedOutputDoc.attributes.type === 'kafka') { + updatedOutputDoc.attributes.connection_type = 'plaintext'; + } + + return { + attributes: updatedOutputDoc.attributes, + }; +}; + +export const migrateOutputEvictionsFromV8100: SavedObjectModelVersionForwardCompatibilityFn = ( + unknownAttributes +) => { + const attributes = unknownAttributes as Output; + if (attributes.type !== 'kafka') { + return attributes; + } + + let updatedAttributes = attributes; + + updatedAttributes = omit(updatedAttributes, ['connection_type']); + + return updatedAttributes; +}; diff --git a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts index 1da8187744091..d50e12541063a 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts @@ -291,7 +291,6 @@ export function transformOutputToFullPolicyOutput( key, compression, compression_level, - auth_type, username, password, sasl, @@ -303,31 +302,69 @@ export function transformOutputToFullPolicyOutput( headers, timeout, broker_timeout, - broker_buffer_size, - broker_ack_reliability, + required_acks, } = output; - /* eslint-enable @typescript-eslint/naming-convention */ + const transformPartition = () => { + if (!partition) return {}; + switch (partition) { + case 'random': + return { + random: { + ...(random?.group_events + ? { group_events: random.group_events } + : { group_events: 1 }), + }, + }; + case 'round_robin': + return { + round_robin: { + ...(round_robin?.group_events + ? { group_events: round_robin.group_events } + : { group_events: 1 }), + }, + }; + case 'hash': + default: + return { hash: { ...(hash?.hash ? { hash: hash.hash } : { hash: '' }) } }; + } + }; + + /* eslint-enable @typescript-eslint/naming-convention */ kafkaData = { client_id, version, key, compression, compression_level, - auth_type, - username, - password, - sasl, - partition, - random, - round_robin, - hash, - topics, - headers, + ...(username ? { username } : {}), + ...(password ? { password } : {}), + ...(sasl ? { sasl } : {}), + partition: transformPartition(), + topics: (topics ?? []).map((topic) => { + const { topic: topicName, ...rest } = topic; + const whenKeys = Object.keys(rest); + + if (whenKeys.length === 0) { + return { topic: topicName }; + } + if (rest.when && rest.when.condition) { + const [keyName, value] = rest.when.condition.split(':'); + + return { + topic: topicName, + when: { + [rest.when.type as string]: { + [keyName.replace(/\s/g, '')]: value.replace(/\s/g, ''), + }, + }, + }; + } + }), + headers: (headers ?? []).filter((item) => item.key !== '' || item.value !== ''), timeout, broker_timeout, - broker_buffer_size, - broker_ack_reliability, + required_acks, }; } diff --git a/x-pack/plugins/fleet/server/services/output.test.ts b/x-pack/plugins/fleet/server/services/output.test.ts index 31efb22834cdb..12abc7c0bec70 100644 --- a/x-pack/plugins/fleet/server/services/output.test.ts +++ b/x-pack/plugins/fleet/server/services/output.test.ts @@ -916,9 +916,9 @@ describe('Output Service', () => { type: 'elasticsearch', hosts: ['http://test:4343'], auth_type: null, + connection_type: null, broker_timeout: null, - broker_ack_reliability: null, - broker_buffer_size: null, + required_acks: null, client_id: null, compression: null, compression_level: null, @@ -1033,13 +1033,14 @@ describe('Output Service', () => { ca_sha256: null, ca_trusted_fingerprint: null, auth_type: null, + connection_type: null, broker_timeout: null, - broker_ack_reliability: null, - broker_buffer_size: null, + required_acks: null, client_id: null, compression: null, compression_level: null, hash: null, + ssl: null, key: null, partition: null, password: null, @@ -1257,10 +1258,13 @@ describe('Output Service', () => { hosts: ['test:4343'], ca_sha256: null, ca_trusted_fingerprint: null, + password: null, + username: null, + ssl: null, + sasl: null, broker_timeout: 10, - broker_ack_reliability: 'Wait for local commit', - broker_buffer_size: 256, - client_id: 'Elastic Agent', + required_acks: 1, + client_id: 'Elastic', compression: 'gzip', compression_level: 4, partition: 'hash', @@ -1285,11 +1289,14 @@ describe('Output Service', () => { expect(soClient.update).toBeCalledWith(expect.anything(), expect.anything(), { hosts: ['test:4343'], broker_timeout: 10, - broker_ack_reliability: 'Wait for local commit', - broker_buffer_size: 256, + required_acks: 1, ca_sha256: null, ca_trusted_fingerprint: null, - client_id: 'Elastic Agent', + password: null, + username: null, + ssl: null, + sasl: null, + client_id: 'Elastic', compression: 'gzip', compression_level: 4, partition: 'hash', @@ -1310,25 +1317,28 @@ describe('Output Service', () => { await outputService.update(soClient, esClientMock, 'output-test', { type: 'kafka', - hosts: ['http://test:4343'], + hosts: ['test:4343'], is_default: true, }); expect(soClient.update).toBeCalledWith(expect.anything(), expect.anything(), { type: 'kafka', - hosts: ['http://test:4343'], + hosts: ['test:4343'], is_default: true, ca_sha256: null, ca_trusted_fingerprint: null, - client_id: 'Elastic Agent', + password: null, + username: null, + ssl: null, + sasl: null, + client_id: 'Elastic', compression: 'gzip', compression_level: 4, partition: 'hash', timeout: 30, version: '1.0.0', broker_timeout: 10, - broker_ack_reliability: 'Wait for local commit', - broker_buffer_size: 256, + required_acks: 1, }); expect(mockedAgentPolicyService.update).toBeCalledWith( expect.anything(), @@ -1354,7 +1364,7 @@ describe('Output Service', () => { 'output-test', { type: 'kafka', - hosts: ['http://test:4343'], + hosts: ['test:4343'], is_default: true, }, { @@ -1364,19 +1374,22 @@ describe('Output Service', () => { expect(soClient.update).toBeCalledWith(expect.anything(), expect.anything(), { type: 'kafka', - hosts: ['http://test:4343'], + hosts: ['test:4343'], is_default: true, ca_sha256: null, ca_trusted_fingerprint: null, - client_id: 'Elastic Agent', + password: null, + username: null, + ssl: null, + sasl: null, + client_id: 'Elastic', compression: 'gzip', compression_level: 4, partition: 'hash', timeout: 30, version: '1.0.0', broker_timeout: 10, - broker_ack_reliability: 'Wait for local commit', - broker_buffer_size: 256, + required_acks: 1, }); expect(mockedAgentPolicyService.update).toBeCalledWith( expect.anything(), @@ -1396,25 +1409,28 @@ describe('Output Service', () => { await outputService.update(soClient, esClientMock, 'output-test', { type: 'kafka', - hosts: ['http://test:4343'], + hosts: ['test:4343'], is_default: true, }); expect(soClient.update).toBeCalledWith(expect.anything(), expect.anything(), { type: 'kafka', - hosts: ['http://test:4343'], + hosts: ['test:4343'], is_default: true, ca_sha256: null, ca_trusted_fingerprint: null, - client_id: 'Elastic Agent', + password: null, + username: null, + ssl: null, + sasl: null, + client_id: 'Elastic', compression: 'gzip', compression_level: 4, partition: 'hash', timeout: 30, version: '1.0.0', broker_timeout: 10, - broker_ack_reliability: 'Wait for local commit', - broker_buffer_size: 256, + required_acks: 1, }); expect(mockedAgentPolicyService.update).toBeCalledWith( expect.anything(), @@ -1438,7 +1454,7 @@ describe('Output Service', () => { 'output-test', { type: 'kafka', - hosts: ['http://test:4343'], + hosts: ['test:4343'], is_default: true, }, { @@ -1448,19 +1464,22 @@ describe('Output Service', () => { expect(soClient.update).toBeCalledWith(expect.anything(), expect.anything(), { type: 'kafka', - hosts: ['http://test:4343'], + hosts: ['test:4343'], is_default: true, ca_sha256: null, ca_trusted_fingerprint: null, - client_id: 'Elastic Agent', + password: null, + username: null, + ssl: null, + sasl: null, + client_id: 'Elastic', compression: 'gzip', compression_level: 4, partition: 'hash', timeout: 30, version: '1.0.0', broker_timeout: 10, - broker_ack_reliability: 'Wait for local commit', - broker_buffer_size: 256, + required_acks: 1, }); expect(mockedAgentPolicyService.update).toBeCalledWith( expect.anything(), diff --git a/x-pack/plugins/fleet/server/services/output.ts b/x-pack/plugins/fleet/server/services/output.ts index d95771eb48238..2cf1764a78f59 100644 --- a/x-pack/plugins/fleet/server/services/output.ts +++ b/x-pack/plugins/fleet/server/services/output.ts @@ -493,7 +493,7 @@ class OutputService { data.compression_level = 4; } if (!output.client_id) { - data.client_id = 'Elastic Agent'; + data.client_id = 'Elastic'; } if (output.username && output.password && !output.sasl?.mechanism) { data.sasl = { @@ -519,11 +519,9 @@ class OutputService { if (!output.broker_timeout) { data.broker_timeout = 10; } - if (!output.broker_ack_reliability) { - data.broker_ack_reliability = kafkaAcknowledgeReliabilityLevel.Commit; - } - if (!output.broker_buffer_size) { - data.broker_buffer_size = 256; + if (output.required_acks === null || output.required_acks === undefined) { + // required_acks can be 0 + data.required_acks = kafkaAcknowledgeReliabilityLevel.Commit; } } @@ -712,6 +710,7 @@ class OutputService { target.key = null; target.compression = null; target.compression_level = null; + target.connection_type = null; target.client_id = null; target.auth_type = null; target.username = null; @@ -725,8 +724,8 @@ class OutputService { target.headers = null; target.timeout = null; target.broker_timeout = null; - target.broker_ack_reliability = null; - target.broker_buffer_size = null; + target.required_acks = null; + target.ssl = null; }; // If the output type changed @@ -766,7 +765,7 @@ class OutputService { updateData.compression_level = 4; } if (!data.client_id) { - updateData.client_id = 'Elastic Agent'; + updateData.client_id = 'Elastic'; } if (data.username && data.password && !data.sasl?.mechanism) { updateData.sasl = { @@ -792,11 +791,9 @@ class OutputService { if (!data.broker_timeout) { updateData.broker_timeout = 10; } - if (!data.broker_ack_reliability) { - updateData.broker_ack_reliability = kafkaAcknowledgeReliabilityLevel.Commit; - } - if (!data.broker_buffer_size) { - updateData.broker_buffer_size = 256; + if (updateData.required_acks === null || updateData.required_acks === undefined) { + // required_acks can be 0 + updateData.required_acks = kafkaAcknowledgeReliabilityLevel.Commit; } } } @@ -808,6 +805,21 @@ class OutputService { updateData.ssl = null; } + if (data.type === outputType.Kafka && updateData.type === outputType.Kafka) { + if (!data.password) { + updateData.password = null; + } + if (!data.username) { + updateData.username = null; + } + if (!data.ssl) { + updateData.ssl = null; + } + if (!data.sasl) { + updateData.sasl = null; + } + } + // ensure only default output exists if (data.is_default) { if (defaultDataOutputId && defaultDataOutputId !== id) { diff --git a/x-pack/plugins/fleet/server/types/models/output.test.ts b/x-pack/plugins/fleet/server/types/models/output.test.ts index 4441630653a99..06edd900fec2a 100644 --- a/x-pack/plugins/fleet/server/types/models/output.test.ts +++ b/x-pack/plugins/fleet/server/types/models/output.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { validateLogstashHost } from './output'; +import { validateKafkaHost, validateLogstashHost } from './output'; describe('Output model', () => { describe('validateLogstashHost', () => { @@ -23,4 +23,22 @@ describe('Output model', () => { ); }); }); + + describe('validateKafkaHost', () => { + it('should support valid host', () => { + expect(validateKafkaHost('test.fr:5044')).toBeUndefined(); + }); + + it('should return an error for an invalid host', () => { + expect(validateKafkaHost('!@#%&!#!@')).toBe( + 'Invalid format. Expected "host:port" without protocol' + ); + }); + + it('should return an error for an invalid host with http scheme', () => { + expect(validateKafkaHost('https://test.fr:5044')).toBe( + 'Invalid format. Expected "host:port" without protocol' + ); + }); + }); }); diff --git a/x-pack/plugins/fleet/server/types/models/output.ts b/x-pack/plugins/fleet/server/types/models/output.ts index b18d2baa25103..845361116d732 100644 --- a/x-pack/plugins/fleet/server/types/models/output.ts +++ b/x-pack/plugins/fleet/server/types/models/output.ts @@ -8,12 +8,13 @@ import { schema } from '@kbn/config-schema'; import { - kafkaAcknowledgeReliabilityLevel, kafkaAuthType, kafkaCompressionType, + kafkaConnectionType, kafkaPartitionType, kafkaSaslMechanism, kafkaTopicWhenType, + kafkaVerificationModes, outputType, } from '../../../common/constants'; @@ -33,6 +34,21 @@ export function validateLogstashHost(val: string) { } } +export const validateKafkaHost = (input: string): string | undefined => { + const parts = input.split(':'); + + if (parts.length !== 2 || !parts[0] || parts[0].includes('://')) { + return 'Invalid format. Expected "host:port" without protocol'; + } + + const port = parseInt(parts[1], 10); + if (isNaN(port) || port < 1 || port > 65535) { + return 'Invalid port number. Expected a number between 1 and 65535'; + } + + return undefined; +}; + /** * Base schemas */ @@ -50,6 +66,14 @@ const BaseSchema = { certificate_authorities: schema.maybe(schema.arrayOf(schema.string())), certificate: schema.maybe(schema.string()), key: schema.maybe(schema.string()), + verification_mode: schema.maybe( + schema.oneOf([ + schema.literal(kafkaVerificationModes.Full), + schema.literal(kafkaVerificationModes.None), + schema.literal(kafkaVerificationModes.Certificate), + schema.literal(kafkaVerificationModes.Strict), + ]) + ), }) ), proxy_id: schema.nullable(schema.string()), @@ -121,15 +145,9 @@ const KafkaTopicsSchema = schema.arrayOf( schema.object({ type: schema.maybe( schema.oneOf([ - schema.literal(kafkaTopicWhenType.And), - schema.literal(kafkaTopicWhenType.Not), - schema.literal(kafkaTopicWhenType.Or), schema.literal(kafkaTopicWhenType.Equals), schema.literal(kafkaTopicWhenType.Contains), schema.literal(kafkaTopicWhenType.Regexp), - schema.literal(kafkaTopicWhenType.HasFields), - schema.literal(kafkaTopicWhenType.Network), - schema.literal(kafkaTopicWhenType.Range), ]) ), condition: schema.maybe(schema.string()), @@ -142,7 +160,7 @@ const KafkaTopicsSchema = schema.arrayOf( export const KafkaSchema = { ...BaseSchema, type: schema.literal(outputType.Kafka), - hosts: schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }), { minSize: 1 }), + hosts: schema.arrayOf(schema.string({ validate: validateKafkaHost }), { minSize: 1 }), version: schema.maybe(schema.string()), key: schema.maybe(schema.string()), compression: schema.maybe( @@ -161,10 +179,20 @@ export const KafkaSchema = { ), client_id: schema.maybe(schema.string()), auth_type: schema.oneOf([ + schema.literal(kafkaAuthType.None), schema.literal(kafkaAuthType.Userpass), schema.literal(kafkaAuthType.Ssl), schema.literal(kafkaAuthType.Kerberos), ]), + connection_type: schema.conditional( + schema.siblingRef('auth_type'), + kafkaAuthType.None, + schema.oneOf([ + schema.literal(kafkaConnectionType.Plaintext), + schema.literal(kafkaConnectionType.Encryption), + ]), + schema.never() + ), username: schema.conditional( schema.siblingRef('auth_type'), kafkaAuthType.Userpass, @@ -206,13 +234,8 @@ export const KafkaSchema = { ), timeout: schema.maybe(schema.number()), broker_timeout: schema.maybe(schema.number()), - broker_buffer_size: schema.maybe(schema.number()), - broker_ack_reliability: schema.maybe( - schema.oneOf([ - schema.literal(kafkaAcknowledgeReliabilityLevel.Commit), - schema.literal(kafkaAcknowledgeReliabilityLevel.Replica), - schema.literal(kafkaAcknowledgeReliabilityLevel.DoNotWait), - ]) + required_acks: schema.maybe( + schema.oneOf([schema.literal(1), schema.literal(0), schema.literal(-1)]) ), }; @@ -220,9 +243,12 @@ const KafkaUpdateSchema = { ...UpdateSchema, ...KafkaSchema, type: schema.maybe(schema.literal(outputType.Kafka)), - hosts: schema.maybe(schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }), { minSize: 1 })), + hosts: schema.maybe( + schema.arrayOf(schema.string({ validate: validateKafkaHost }), { minSize: 1 }) + ), auth_type: schema.maybe( schema.oneOf([ + schema.literal(kafkaAuthType.None), schema.literal(kafkaAuthType.Userpass), schema.literal(kafkaAuthType.Ssl), schema.literal(kafkaAuthType.Kerberos), diff --git a/x-pack/plugins/fleet/server/types/so_attributes.ts b/x-pack/plugins/fleet/server/types/so_attributes.ts index 13ccff751c38d..941f27cde7c4d 100644 --- a/x-pack/plugins/fleet/server/types/so_attributes.ts +++ b/x-pack/plugins/fleet/server/types/so_attributes.ts @@ -14,6 +14,7 @@ import type { OutputType, ShipperOutput, KafkaAcknowledgeReliabilityLevel, + KafkaConnectionTypeType, } from '../../common/types'; import type { AgentType, FleetServerAgentComponent } from '../../common/types/models'; @@ -159,6 +160,7 @@ export interface OutputSoKafkaAttributes extends OutputSoBaseAttributes { compression?: ValueOf; compression_level?: number; auth_type?: ValueOf; + connection_type?: ValueOf; username?: string; password?: string; sasl?: { @@ -188,8 +190,7 @@ export interface OutputSoKafkaAttributes extends OutputSoBaseAttributes { }>; timeout?: number; broker_timeout?: number; - broker_buffer_size?: number; - broker_ack_reliability?: ValueOf; + required_acks?: ValueOf; } export type OutputSOAttributes = diff --git a/x-pack/test/fleet_api_integration/apis/outputs/crud.ts b/x-pack/test/fleet_api_integration/apis/outputs/crud.ts index c870e4bca0ab1..3cc860433eb69 100644 --- a/x-pack/test/fleet_api_integration/apis/outputs/crud.ts +++ b/x-pack/test/fleet_api_integration/apis/outputs/crud.ts @@ -197,7 +197,7 @@ export default function (providerContext: FtrProviderContext) { .send({ name: 'My Kafka Output', type: 'kafka', - hosts: ['https://test.fr'], + hosts: ['test.fr:2000'], auth_type: 'user_pass', username: 'user', password: 'pass', @@ -565,7 +565,7 @@ export default function (providerContext: FtrProviderContext) { .send({ name: 'My Kafka Output', type: 'kafka', - hosts: ['https://test.fr'], + hosts: ['test.fr:2000'], auth_type: 'user_pass', username: 'user', password: 'pass', @@ -579,15 +579,14 @@ export default function (providerContext: FtrProviderContext) { is_default_monitoring: false, name: 'My Kafka Output', type: 'kafka', - hosts: ['https://test.fr'], + hosts: ['test.fr:2000'], auth_type: 'user_pass', username: 'user', password: 'pass', topics: [{ topic: 'topic1' }], broker_timeout: 10, - broker_ack_reliability: 'Wait for local commit', - broker_buffer_size: 256, - client_id: 'Elastic Agent', + required_acks: 1, + client_id: 'Elastic', compression: 'gzip', compression_level: 4, sasl: { @@ -606,7 +605,7 @@ export default function (providerContext: FtrProviderContext) { .send({ name: 'Default Kafka Output', type: 'kafka', - hosts: ['https://test.fr'], + hosts: ['test.fr:2000'], auth_type: 'user_pass', username: 'user', password: 'pass', @@ -619,7 +618,7 @@ export default function (providerContext: FtrProviderContext) { expect(itemWithoutId).to.eql({ name: 'Default Kafka Output', type: 'kafka', - hosts: ['https://test.fr'], + hosts: ['test.fr:2000'], auth_type: 'user_pass', username: 'user', password: 'pass', @@ -627,9 +626,8 @@ export default function (providerContext: FtrProviderContext) { is_default: true, is_default_monitoring: false, broker_timeout: 10, - broker_ack_reliability: 'Wait for local commit', - broker_buffer_size: 256, - client_id: 'Elastic Agent', + required_acks: 1, + client_id: 'Elastic', compression: 'gzip', compression_level: 4, sasl: { @@ -847,7 +845,7 @@ export default function (providerContext: FtrProviderContext) { .send({ name: 'Kafka Output', type: 'kafka', - hosts: ['https://test.fr'], + hosts: ['test.fr:2000'], auth_type: 'user_pass', username: 'user', password: 'pass', @@ -960,7 +958,7 @@ export default function (providerContext: FtrProviderContext) { const kafkaOutputPayload = { name: 'Output to delete test', type: 'kafka', - hosts: ['https://test.fr'], + hosts: ['test.fr:2000'], auth_type: 'user_pass', username: 'user', password: 'pass', From 764fa8aaef38149a2bd5151773887974ac845add Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Wed, 9 Aug 2023 17:02:02 +0100 Subject: [PATCH 15/22] [UserProfiles] Move React hook to package (#162888) --- packages/kbn-user-profile-components/index.ts | 13 +- .../src/hooks/index.ts | 9 + .../hooks}/use_update_user_profile.test.tsx | 114 ++++---- .../src/hooks/use_update_user_profile.tsx | 136 +++++++++ .../src/services.tsx | 109 +++++++ .../kbn-user-profile-components/src/types.ts | 47 ++++ .../src/user_avatar.tsx | 3 +- .../src/user_profile.ts | 24 +- .../src/user_tooltip.tsx | 3 +- .../kbn-user-profile-components/tsconfig.json | 6 +- .../cloud_links/kibana.jsonc | 3 + .../maybe_add_cloud_links.test.ts.snap | 51 ++++ .../maybe_add_cloud_links.test.ts | 266 ++++-------------- .../maybe_add_cloud_links.ts | 30 +- .../theme_darkmode_hook.ts | 7 +- .../theme_darkmode_toggle.test.tsx | 28 +- .../theme_darkmode_toggle.tsx | 19 +- .../maybe_add_cloud_links/user_menu_links.tsx | 10 +- .../cloud_links/public/plugin.tsx | 4 +- .../cloud_links/tsconfig.json | 3 + x-pack/plugins/security/common/index.ts | 1 - x-pack/plugins/security/common/model/index.ts | 1 - .../security/common/model/user_profile.ts | 29 +- .../account_management_app.tsx | 19 +- .../public/account_management/index.ts | 1 - .../account_management/user_profile/index.ts | 2 - .../user_profile/use_update_user_profile.tsx | 150 ---------- .../user_profile/user_profile.tsx | 24 +- .../user_profile/user_profile_api_client.ts | 2 +- x-pack/plugins/security/public/index.ts | 1 - x-pack/plugins/security/public/mocks.ts | 3 - .../nav_control/nav_control_component.tsx | 3 +- .../plugins/security/public/plugin.test.tsx | 3 - x-pack/plugins/security/public/plugin.tsx | 15 - .../translations/translations/fr-FR.json | 3 - .../translations/translations/ja-JP.json | 3 - .../translations/translations/zh-CN.json | 3 - .../common/lib/api/user_profiles.ts | 7 +- 38 files changed, 584 insertions(+), 571 deletions(-) create mode 100644 packages/kbn-user-profile-components/src/hooks/index.ts rename {x-pack/plugins/security/public/account_management/user_profile => packages/kbn-user-profile-components/src/hooks}/use_update_user_profile.test.tsx (52%) create mode 100644 packages/kbn-user-profile-components/src/hooks/use_update_user_profile.tsx create mode 100644 packages/kbn-user-profile-components/src/services.tsx create mode 100644 packages/kbn-user-profile-components/src/types.ts create mode 100644 x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/__snapshots__/maybe_add_cloud_links.test.ts.snap delete mode 100644 x-pack/plugins/security/public/account_management/user_profile/use_update_user_profile.tsx diff --git a/packages/kbn-user-profile-components/index.ts b/packages/kbn-user-profile-components/index.ts index 5f8d1db6fcf62..c3f5650c17837 100644 --- a/packages/kbn-user-profile-components/index.ts +++ b/packages/kbn-user-profile-components/index.ts @@ -19,6 +19,17 @@ export { getUserDisplayName } from './src/user_profile'; export type { UserProfile, UserProfileUserInfo, - UserProfileAvatarData, GetUserDisplayNameParams, } from './src/user_profile'; +export type { + UserProfileData, + UserSettingsData, + DarkModeValue, + UserProfileAvatarData, +} from './src/types'; +export { useUpdateUserProfile, type UpdateUserProfileHook } from './src/hooks'; +export { + UserProfilesKibanaProvider, + UserProfilesProvider, + type UserProfilesKibanaDependencies, +} from './src/services'; diff --git a/packages/kbn-user-profile-components/src/hooks/index.ts b/packages/kbn-user-profile-components/src/hooks/index.ts new file mode 100644 index 0000000000000..c3f6c8f3b973f --- /dev/null +++ b/packages/kbn-user-profile-components/src/hooks/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { useUpdateUserProfile, type UpdateUserProfileHook } from './use_update_user_profile'; diff --git a/x-pack/plugins/security/public/account_management/user_profile/use_update_user_profile.test.tsx b/packages/kbn-user-profile-components/src/hooks/use_update_user_profile.test.tsx similarity index 52% rename from x-pack/plugins/security/public/account_management/user_profile/use_update_user_profile.test.tsx rename to packages/kbn-user-profile-components/src/hooks/use_update_user_profile.test.tsx index 6690e9b6cf946..3f3621b8aae18 100644 --- a/x-pack/plugins/security/public/account_management/user_profile/use_update_user_profile.test.tsx +++ b/packages/kbn-user-profile-components/src/hooks/use_update_user_profile.test.tsx @@ -1,58 +1,82 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 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 { act, renderHook } from '@testing-library/react-hooks'; -import { BehaviorSubject, first, lastValueFrom } from 'rxjs'; -import { coreMock } from '@kbn/core/public/mocks'; - -import { getUseUpdateUserProfile } from './use_update_user_profile'; -import { UserProfileAPIClient } from './user_profile_api_client'; +import React from 'react'; +import { act, renderHook, type WrapperComponent } from '@testing-library/react-hooks'; +import { BehaviorSubject, first, lastValueFrom, of } from 'rxjs'; -const { notifications, http } = coreMock.createStart(); -const userProfileApiClient = new UserProfileAPIClient(http); -const useUpdateUserProfile = getUseUpdateUserProfile({ - apiClient: userProfileApiClient, - notifications, -}); +import { coreMock } from '@kbn/core/public/mocks'; -describe('useUpdateUserProfile', () => { - let spy: jest.SpyInstance; +import { useUpdateUserProfile } from './use_update_user_profile'; +import { UserProfilesKibanaProvider } from '../services'; + +const core = coreMock.createStart(); +const security = { + authc: {}, + navControlService: {}, + userProfiles: { + getCurrent: jest.fn(), + bulkGet: jest.fn(), + suggest: jest.fn(), + update: jest.fn(), + userProfile$: of({}), + }, + uiApi: {}, +}; + +const { http, notifications } = core; + +const wrapper: WrapperComponent = ({ children }) => ( + () => () => undefined} + > + {children} + +); + +describe('useUpdateUserProfile() hook', () => { + const updateUserProfiles = jest.fn(); beforeEach(() => { - spy = jest.spyOn(userProfileApiClient, 'update'); + security.userProfiles = { + ...security.userProfiles, + update: updateUserProfiles, + userProfile$: of({}), + }; + + updateUserProfiles.mockReset().mockResolvedValue({}); http.get.mockReset(); http.post.mockReset().mockResolvedValue(undefined); notifications.toasts.addSuccess.mockReset(); }); - afterEach(() => { - spy.mockRestore(); - }); - test('should call the apiClient with the updated user profile data', async () => { - const { result } = renderHook(() => useUpdateUserProfile()); + const { result } = renderHook(() => useUpdateUserProfile(), { wrapper }); const { update } = result.current; await act(async () => { update({ userSettings: { darkMode: 'dark' } }); }); - expect(spy).toHaveBeenCalledWith({ userSettings: { darkMode: 'dark' } }); + expect(updateUserProfiles).toHaveBeenCalledWith({ userSettings: { darkMode: 'dark' } }); }); test('should update the isLoading state while updating', async () => { - const { result, waitForNextUpdate } = renderHook(() => useUpdateUserProfile()); - const { update } = result.current; - const httpPostDone = new BehaviorSubject(false); - - http.post.mockImplementationOnce(async () => { - await lastValueFrom(httpPostDone.pipe(first((v) => v === true))); + const updateDone = new BehaviorSubject(false); + updateUserProfiles.mockImplementationOnce(async () => { + await lastValueFrom(updateDone.pipe(first((v) => v === true))); }); + const { result, waitForNextUpdate } = renderHook(() => useUpdateUserProfile(), { wrapper }); + const { update } = result.current; + expect(result.current.isLoading).toBeFalsy(); await act(async () => { @@ -61,16 +85,18 @@ describe('useUpdateUserProfile', () => { expect(result.current.isLoading).toBeTruthy(); - httpPostDone.next(true); // Resolve the http.post promise + updateDone.next(true); // Resolve the http.post promise await waitForNextUpdate(); expect(result.current.isLoading).toBeFalsy(); }); test('should show a success notification by default', async () => { - const { result } = renderHook(() => useUpdateUserProfile()); + const { result } = renderHook(() => useUpdateUserProfile(), { wrapper }); const { update } = result.current; + expect(notifications.toasts.addSuccess).not.toHaveBeenCalled(); + await act(async () => { await update({ userSettings: { darkMode: 'dark' } }); }); @@ -88,11 +114,7 @@ describe('useUpdateUserProfile', () => { return true; }; - const { result } = renderHook(() => - useUpdateUserProfile({ - pageReloadChecker, - }) - ); + const { result } = renderHook(() => useUpdateUserProfile({ pageReloadChecker }), { wrapper }); const { update } = result.current; await act(async () => { @@ -114,21 +136,17 @@ describe('useUpdateUserProfile', () => { const pageReloadChecker = jest.fn(); const initialValue = { foo: 'bar' }; - http.get.mockReset().mockResolvedValue({ data: initialValue }); - const userProfileApiClient2 = new UserProfileAPIClient(http); - await userProfileApiClient2.getCurrent(); // Sets the initial value of the userProfile$ Observable - - const { result } = renderHook(() => - getUseUpdateUserProfile({ - apiClient: userProfileApiClient2, - notifications, - })({ - pageReloadChecker, - }) - ); + + security.userProfiles = { + ...security.userProfiles, + userProfile$: of(initialValue), + }; + + const { result } = renderHook(() => useUpdateUserProfile({ pageReloadChecker }), { wrapper }); const { update } = result.current; const nextValue = { userSettings: { darkMode: 'light' as const } }; + await act(async () => { await update(nextValue); }); diff --git a/packages/kbn-user-profile-components/src/hooks/use_update_user_profile.tsx b/packages/kbn-user-profile-components/src/hooks/use_update_user_profile.tsx new file mode 100644 index 0000000000000..3e015fe92eac5 --- /dev/null +++ b/packages/kbn-user-profile-components/src/hooks/use_update_user_profile.tsx @@ -0,0 +1,136 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React, { useCallback, useRef, useState } from 'react'; +import useObservable from 'react-use/lib/useObservable'; +import { i18n } from '@kbn/i18n'; + +import type { UserProfileData } from '../types'; +import { useUserProfiles } from '../services'; + +interface Props { + notificationSuccess?: { + /** Flag to indicate if a notification is shown after update. Default: `true` */ + enabled?: boolean; + /** Customize the title of the notification */ + title?: string; + /** Customize the "page reload needed" text of the notification */ + pageReloadText?: string; + }; + /** Predicate to indicate if the update requires a page reload */ + pageReloadChecker?: ( + previsous: UserProfileData | null | undefined, + next: UserProfileData + ) => boolean; +} + +const i18nTexts = { + notificationSuccess: { + title: i18n.translate( + 'userProfileComponents.updateUserProfile.notification.submitSuccessTitle', + { + defaultMessage: 'Profile updated', + } + ), + pageReloadText: i18n.translate( + 'userProfileComponents.updateUserProfile.notification.requiresPageReloadDescription', + { + defaultMessage: 'One or more settings require you to reload the page to take effect.', + } + ), + }, +}; + +export const useUpdateUserProfile = ({ + notificationSuccess = {}, + pageReloadChecker, +}: Props = {}) => { + const { userProfileApiClient, notifySuccess } = useUserProfiles(); + const { userProfile$ } = userProfileApiClient; + const { + enabled: notificationSuccessEnabled = true, + title: notificationTitle = i18nTexts.notificationSuccess.title, + pageReloadText = i18nTexts.notificationSuccess.pageReloadText, + } = notificationSuccess; + const [isLoading, setIsLoading] = useState(false); + const userProfileData = useObservable(userProfile$); + // Keep a snapshot before updating the user profile so we can compare previous and updated values + const userProfileSnapshot = useRef(); + + const showSuccessNotification = useCallback( + ({ isRefreshRequired = false }: { isRefreshRequired?: boolean } = {}) => { + if (isRefreshRequired) { + notifySuccess( + { + title: notificationTitle, + text: ( + + +

    {pageReloadText}

    + window.location.reload()} + data-test-subj="windowReloadButton" + > + {i18n.translate( + 'userProfileComponents.updateUserProfile.notification.requiresPageReloadButtonLabel', + { + defaultMessage: 'Reload page', + } + )} + +
    +
    + ), + }, + { + durationMs: 1000 * 60 * 5, + } + ); + } else { + notifySuccess({ title: notificationTitle }); + } + }, + [notificationTitle, notifySuccess, pageReloadText] + ); + + const onUserProfileUpdate = useCallback( + (updatedData: UserProfileData) => { + setIsLoading(false); + + if (notificationSuccessEnabled) { + const isRefreshRequired = pageReloadChecker?.(userProfileSnapshot.current, updatedData); + showSuccessNotification({ isRefreshRequired }); + } + }, + [notificationSuccessEnabled, showSuccessNotification, pageReloadChecker] + ); + + const update = useCallback( + (updatedData: D) => { + userProfileSnapshot.current = userProfileData; + setIsLoading(true); + return userProfileApiClient.update(updatedData).then(() => onUserProfileUpdate(updatedData)); + }, + [userProfileApiClient, onUserProfileUpdate, userProfileData] + ); + + return { + /** Update the user profile */ + update, + /** Handler to show a notification after the user profile has been updated */ + showSuccessNotification, + /** The current user profile data */ + userProfileData, + /** Flag to indicate if currently updating */ + isLoading, + }; +}; + +export type UpdateUserProfileHook = typeof useUpdateUserProfile; diff --git a/packages/kbn-user-profile-components/src/services.tsx b/packages/kbn-user-profile-components/src/services.tsx new file mode 100644 index 0000000000000..0e08ca911eb61 --- /dev/null +++ b/packages/kbn-user-profile-components/src/services.tsx @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { FC, useContext } from 'react'; +import type { Observable } from 'rxjs'; +import type { NotificationsStart, ToastOptions } from '@kbn/core-notifications-browser'; +import type { MountPoint } from '@kbn/core-mount-utils-browser'; +import type { ThemeServiceStart } from '@kbn/core-theme-browser'; + +import type { UserProfileAPIClient } from './types'; + +type NotifyFn = ( + data: { title: string; text?: JSX.Element }, + options?: { durationMs?: number } +) => void; + +export interface Services { + userProfileApiClient: UserProfileAPIClient; + notifySuccess: NotifyFn; +} + +const UserProfilesContext = React.createContext(null); + +/** + * Abstract external service Provider. + */ +export const UserProfilesProvider: FC = ({ children, ...services }) => { + return {children}; +}; + +/** + * Kibana-specific service types. + */ +export interface UserProfilesKibanaDependencies { + /** CoreStart contract */ + core: { + notifications: NotificationsStart; + theme: ThemeServiceStart; + }; + security: { + userProfiles: UserProfileAPIClient; + }; + /** + * Handler from the '@kbn/kibana-react-plugin/public' Plugin + * + * ``` + * import { toMountPoint } from '@kbn/kibana-react-plugin/public'; + * ``` + */ + toMountPoint: ( + node: React.ReactNode, + options?: { theme$: Observable<{ readonly darkMode: boolean }> } + ) => MountPoint; +} + +/** + * Kibana-specific Provider that maps to known dependency types. + */ +export const UserProfilesKibanaProvider: FC = ({ + children, + ...services +}) => { + const { + core: { notifications, theme }, + security: { userProfiles: userProfileApiClient }, + toMountPoint, + } = services; + + return ( + { + const toastOptions: ToastOptions = {}; + if (options?.durationMs) { + toastOptions.toastLifeTimeMs = options.durationMs; + } + notifications.toasts.addSuccess( + { + title, + text: text ? toMountPoint(text, { theme$: theme.theme$ }) : undefined, + }, + toastOptions + ); + }} + > + {children} + + ); +}; + +/** + * React hook for accessing pre-wired services. + */ +export function useUserProfiles() { + const context = useContext(UserProfilesContext); + + if (!context) { + throw new Error( + 'UserProfilesContext is missing. Ensure your component or React root is wrapped with or .' + ); + } + + return context; +} diff --git a/packages/kbn-user-profile-components/src/types.ts b/packages/kbn-user-profile-components/src/types.ts new file mode 100644 index 0000000000000..77b6895756bdf --- /dev/null +++ b/packages/kbn-user-profile-components/src/types.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Observable } from 'rxjs'; + +/** + * Avatar stored in user profile. + */ +export interface UserProfileAvatarData { + /** + * Optional initials (two letters) of the user to use as avatar if avatar picture isn't specified. + */ + initials?: string; + /** + * Background color of the avatar when initials are used. + */ + color?: string; + /** + * Base64 data URL for the user avatar image. + */ + imageUrl?: string | null; +} + +export type DarkModeValue = '' | 'dark' | 'light'; + +/** + * User settings stored in the data object of the User Profile + */ +export interface UserSettingsData { + darkMode?: DarkModeValue; +} + +export interface UserProfileData { + avatar?: UserProfileAvatarData; + userSettings?: UserSettingsData; + [key: string]: unknown; +} + +export interface UserProfileAPIClient { + userProfile$: Observable; + update: (data: D) => Promise; +} diff --git a/packages/kbn-user-profile-components/src/user_avatar.tsx b/packages/kbn-user-profile-components/src/user_avatar.tsx index 2413694317c27..1b2a2152f27fc 100644 --- a/packages/kbn-user-profile-components/src/user_avatar.tsx +++ b/packages/kbn-user-profile-components/src/user_avatar.tsx @@ -10,8 +10,9 @@ import type { EuiAvatarProps } from '@elastic/eui'; import { EuiAvatar, useEuiTheme } from '@elastic/eui'; import type { FunctionComponent } from 'react'; import React from 'react'; +import { UserProfileAvatarData } from './types'; -import type { UserProfile, UserProfileUserInfo, UserProfileAvatarData } from './user_profile'; +import type { UserProfile, UserProfileUserInfo } from './user_profile'; import { getUserAvatarColor, getUserAvatarInitials, diff --git a/packages/kbn-user-profile-components/src/user_profile.ts b/packages/kbn-user-profile-components/src/user_profile.ts index 4d0803ad6dbec..965f5e9706e8e 100644 --- a/packages/kbn-user-profile-components/src/user_profile.ts +++ b/packages/kbn-user-profile-components/src/user_profile.ts @@ -7,6 +7,7 @@ */ import { VISUALIZATION_COLORS } from '@elastic/eui'; +import type { UserProfileAvatarData, UserProfileData } from './types'; /** * IMPORTANT: @@ -60,29 +61,6 @@ export interface UserProfileUserInfo { full_name?: string; } -/** - * Placeholder for data stored in user profile. - */ -export type UserProfileData = Record; - -/** - * Avatar stored in user profile. - */ -export interface UserProfileAvatarData { - /** - * Optional initials (two letters) of the user to use as avatar if avatar picture isn't specified. - */ - initials?: string; - /** - * Background color of the avatar when initials are used. - */ - color?: string; - /** - * Base64 data URL for the user avatar image. - */ - imageUrl?: string | null; -} - export const USER_AVATAR_FALLBACK_CODE_POINT = 97; // code point for lowercase "a" export const USER_AVATAR_MAX_INITIALS = 2; diff --git a/packages/kbn-user-profile-components/src/user_tooltip.tsx b/packages/kbn-user-profile-components/src/user_tooltip.tsx index c2678996aebb3..76b7ca1414274 100644 --- a/packages/kbn-user-profile-components/src/user_tooltip.tsx +++ b/packages/kbn-user-profile-components/src/user_tooltip.tsx @@ -11,9 +11,10 @@ import { EuiToolTip, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import type { FunctionComponent } from 'react'; import React from 'react'; -import type { UserProfileUserInfo, UserProfileAvatarData } from './user_profile'; +import type { UserProfileUserInfo } from './user_profile'; import { UserAvatar } from './user_avatar'; import { getUserDisplayName } from './user_profile'; +import { UserProfileAvatarData } from './types'; /** * Props of {@link UserToolTip} component diff --git a/packages/kbn-user-profile-components/tsconfig.json b/packages/kbn-user-profile-components/tsconfig.json index 6f64745691be8..a602ca242d733 100644 --- a/packages/kbn-user-profile-components/tsconfig.json +++ b/packages/kbn-user-profile-components/tsconfig.json @@ -13,7 +13,11 @@ ], "kbn_references": [ "@kbn/i18n", - "@kbn/i18n-react" + "@kbn/i18n-react", + "@kbn/core-notifications-browser", + "@kbn/core", + "@kbn/core-theme-browser", + "@kbn/core-mount-utils-browser", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/cloud_integrations/cloud_links/kibana.jsonc b/x-pack/plugins/cloud_integrations/cloud_links/kibana.jsonc index b9b9a0f629b64..4b6625f842f79 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/kibana.jsonc +++ b/x-pack/plugins/cloud_integrations/cloud_links/kibana.jsonc @@ -11,6 +11,9 @@ "cloud", "security", "guidedOnboarding" + ], + "requiredBundles": [ + "kibanaReact" ] } } diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/__snapshots__/maybe_add_cloud_links.test.ts.snap b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/__snapshots__/maybe_add_cloud_links.test.ts.snap new file mode 100644 index 0000000000000..7a957943fe2f0 --- /dev/null +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/__snapshots__/maybe_add_cloud_links.test.ts.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`maybeAddCloudLinks when cloud enabled and it fails to fetch the user, it sets the links 2`] = ` +Array [ + Object { + "href": "profile-url", + "iconType": "user", + "label": "Profile", + "order": 100, + "setAsProfile": true, + }, + Object { + "href": "billing-url", + "iconType": "visGauge", + "label": "Billing", + "order": 200, + }, + Object { + "href": "organization-url", + "iconType": "gear", + "label": "Organization", + "order": 300, + }, + Any, +] +`; + +exports[`maybeAddCloudLinks when cloud enabled and the user is an Elastic Cloud user, it sets the links 2`] = ` +Array [ + Object { + "href": "profile-url", + "iconType": "user", + "label": "Profile", + "order": 100, + "setAsProfile": true, + }, + Object { + "href": "billing-url", + "iconType": "visGauge", + "label": "Billing", + "order": 200, + }, + Object { + "href": "organization-url", + "iconType": "gear", + "label": "Organization", + "order": 300, + }, + Any, +] +`; diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.test.ts b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.test.ts index f2e14d1a08526..b9045fdc9a59f 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.test.ts +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.test.ts @@ -14,12 +14,11 @@ import { maybeAddCloudLinks } from './maybe_add_cloud_links'; describe('maybeAddCloudLinks', () => { it('should skip if cloud is disabled', async () => { const security = securityMock.createStart(); + const core = coreMock.createStart(); maybeAddCloudLinks({ + core, security, - chrome: coreMock.createStart().chrome, cloud: { ...cloudMock.createStart(), isCloudEnabled: false }, - docLinks: coreMock.createStart().docLinks, - uiSettingsClient: coreMock.createStart().uiSettings, }); // Since there's a promise, let's wait for the next tick await new Promise((resolve) => process.nextTick(resolve)); @@ -31,13 +30,12 @@ describe('maybeAddCloudLinks', () => { security.authc.getCurrentUser.mockResolvedValue( securityMock.createMockAuthenticatedUser({ elastic_cloud_user: true }) ); - const { chrome, docLinks, uiSettings } = coreMock.createStart(); + const core = coreMock.createStart(); + const { chrome } = core; maybeAddCloudLinks({ security, - chrome, + core, cloud: { ...cloudMock.createStart(), isCloudEnabled: true }, - docLinks, - uiSettingsClient: uiSettings, }); // Since there's a promise, let's wait for the next tick await new Promise((resolve) => process.nextTick(resolve)); @@ -53,104 +51,28 @@ describe('maybeAddCloudLinks', () => { ] `); expect(security.navControlService.addUserMenuLinks).toHaveBeenCalledTimes(1); - expect(security.navControlService.addUserMenuLinks.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "href": "profile-url", - "iconType": "user", - "label": "Profile", - "order": 100, - "setAsProfile": true, - }, - Object { - "href": "billing-url", - "iconType": "visGauge", - "label": "Billing", - "order": 200, - }, - Object { - "href": "organization-url", - "iconType": "gear", - "label": "Organization", - "order": 300, - }, - Object { - "content": , - "href": "", - "iconType": "", - "label": "", - "order": 400, - }, - ], - ] - `); + expect(security.navControlService.addUserMenuLinks.mock.calls[0][0]).toMatchSnapshot([ + { + href: 'profile-url', + iconType: 'user', + label: 'Profile', + order: 100, + setAsProfile: true, + }, + { + href: 'billing-url', + iconType: 'visGauge', + label: 'Billing', + order: 200, + }, + { + href: 'organization-url', + iconType: 'gear', + label: 'Organization', + order: 300, + }, + expect.any(Object), + ]); expect(chrome.setHelpMenuLinks).toHaveBeenCalledTimes(1); expect(chrome.setHelpMenuLinks.mock.calls[0]).toMatchInlineSnapshot(` @@ -176,13 +98,12 @@ describe('maybeAddCloudLinks', () => { it('when cloud enabled and it fails to fetch the user, it sets the links', async () => { const security = securityMock.createStart(); security.authc.getCurrentUser.mockRejectedValue(new Error('Something went terribly wrong')); - const { chrome, docLinks, uiSettings } = coreMock.createStart(); + const core = coreMock.createStart(); + const { chrome } = core; maybeAddCloudLinks({ security, - chrome, + core, cloud: { ...cloudMock.createStart(), isCloudEnabled: true }, - docLinks, - uiSettingsClient: uiSettings, }); // Since there's a promise, let's wait for the next tick await new Promise((resolve) => process.nextTick(resolve)); @@ -198,104 +119,28 @@ describe('maybeAddCloudLinks', () => { ] `); expect(security.navControlService.addUserMenuLinks).toHaveBeenCalledTimes(1); - expect(security.navControlService.addUserMenuLinks.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "href": "profile-url", - "iconType": "user", - "label": "Profile", - "order": 100, - "setAsProfile": true, - }, - Object { - "href": "billing-url", - "iconType": "visGauge", - "label": "Billing", - "order": 200, - }, - Object { - "href": "organization-url", - "iconType": "gear", - "label": "Organization", - "order": 300, - }, - Object { - "content": , - "href": "", - "iconType": "", - "label": "", - "order": 400, - }, - ], - ] - `); + expect(security.navControlService.addUserMenuLinks.mock.calls[0][0]).toMatchSnapshot([ + { + href: 'profile-url', + iconType: 'user', + label: 'Profile', + order: 100, + setAsProfile: true, + }, + { + href: 'billing-url', + iconType: 'visGauge', + label: 'Billing', + order: 200, + }, + { + href: 'organization-url', + iconType: 'gear', + label: 'Organization', + order: 300, + }, + expect.any(Object), + ]); expect(chrome.setHelpMenuLinks).toHaveBeenCalledTimes(1); expect(chrome.setHelpMenuLinks.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -322,13 +167,12 @@ describe('maybeAddCloudLinks', () => { security.authc.getCurrentUser.mockResolvedValue( securityMock.createMockAuthenticatedUser({ elastic_cloud_user: false }) ); - const { chrome, docLinks, uiSettings } = coreMock.createStart(); + const core = coreMock.createStart(); + const { chrome } = core; maybeAddCloudLinks({ security, - chrome, + core, cloud: { ...cloudMock.createStart(), isCloudEnabled: true }, - docLinks, - uiSettingsClient: uiSettings, }); // Since there's a promise, let's wait for the next tick await new Promise((resolve) => process.nextTick(resolve)); diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.ts b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.ts index 1becd2cdf7254..33fb4df7bfce2 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.ts +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.ts @@ -9,28 +9,18 @@ import { catchError, defer, filter, map, of, combineLatest } from 'rxjs'; import { i18n } from '@kbn/i18n'; import type { CloudStart } from '@kbn/cloud-plugin/public'; -import type { ChromeStart } from '@kbn/core/public'; +import type { CoreStart } from '@kbn/core/public'; import type { SecurityPluginStart } from '@kbn/security-plugin/public'; -import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; -import type { DocLinksStart } from '@kbn/core-doc-links-browser'; import { createUserMenuLinks } from './user_menu_links'; import { createHelpMenuLinks } from './help_menu_links'; export interface MaybeAddCloudLinksDeps { + core: CoreStart; security: SecurityPluginStart; - chrome: ChromeStart; cloud: CloudStart; - docLinks: DocLinksStart; - uiSettingsClient: IUiSettingsClient; } -export function maybeAddCloudLinks({ - security, - chrome, - cloud, - docLinks, - uiSettingsClient, -}: MaybeAddCloudLinksDeps): void { +export function maybeAddCloudLinks({ core, security, cloud }: MaybeAddCloudLinksDeps): void { const userObservable = defer(() => security.authc.getCurrentUser()).pipe( // Check if user is a cloud user. map((user) => user.elastic_cloud_user), @@ -39,7 +29,7 @@ export function maybeAddCloudLinks({ filter((isElasticCloudUser) => isElasticCloudUser === true), map(() => { if (cloud.deploymentUrl) { - chrome.setCustomNavLink({ + core.chrome.setCustomNavLink({ title: i18n.translate('xpack.cloudLinks.deploymentLinkLabel', { defaultMessage: 'Manage this deployment', }), @@ -47,22 +37,26 @@ export function maybeAddCloudLinks({ href: cloud.deploymentUrl, }); } - const userMenuLinks = createUserMenuLinks({ cloud, security, uiSettingsClient }); + const userMenuLinks = createUserMenuLinks({ + core, + cloud, + security, + }); security.navControlService.addUserMenuLinks(userMenuLinks); }) ); - const helpObservable = chrome.getHelpSupportUrl$(); + const helpObservable = core.chrome.getHelpSupportUrl$(); if (cloud.isCloudEnabled) { combineLatest({ user: userObservable, helpSupportUrl: helpObservable }).subscribe( ({ helpSupportUrl }) => { const helpMenuLinks = createHelpMenuLinks({ - docLinks, + docLinks: core.docLinks, helpSupportUrl, }); - chrome.setHelpMenuLinks(helpMenuLinks); + core.chrome.setHelpMenuLinks(helpMenuLinks); } ); } diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/theme_darkmode_hook.ts b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/theme_darkmode_hook.ts index 75d6ae4d1d329..c0a4fcc3a09ac 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/theme_darkmode_hook.ts +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/theme_darkmode_hook.ts @@ -7,21 +7,20 @@ import { useCallback, useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; -import type { SecurityPluginStart } from '@kbn/security-plugin/public'; import { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; +import { useUpdateUserProfile } from '@kbn/user-profile-components'; interface Deps { uiSettingsClient: IUiSettingsClient; - security: SecurityPluginStart; } -export const useThemeDarkmodeToggle = ({ uiSettingsClient, security }: Deps) => { +export const useThemeDarkmodeToggle = ({ uiSettingsClient }: Deps) => { const [isDarkModeOn, setIsDarkModeOn] = useState(false); // If a value is set in kibana.yml (uiSettings.overrides.theme:darkMode) // we don't allow the user to change the theme color. const valueSetInKibanaConfig = uiSettingsClient.isOverridden('theme:darkMode'); - const { userProfileData, isLoading, update } = security.hooks.useUpdateUserProfile({ + const { userProfileData, isLoading, update } = useUpdateUserProfile({ notificationSuccess: { title: i18n.translate('xpack.cloudLinks.userMenuLinks.darkMode.successNotificationTitle', { defaultMessage: 'Color theme updated', diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/theme_darkmode_toggle.test.tsx b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/theme_darkmode_toggle.test.tsx index 2bebdad488498..6b06cd64b9e23 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/theme_darkmode_toggle.test.tsx +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/theme_darkmode_toggle.test.tsx @@ -11,18 +11,22 @@ import '@testing-library/jest-dom'; import { coreMock } from '@kbn/core/public/mocks'; import { securityMock } from '@kbn/security-plugin/public/mocks'; -import { ThemDarkModeToggle } from './theme_darkmode_toggle'; +import { ThemeDarkModeToggle } from './theme_darkmode_toggle'; -describe('ThemDarkModeToggle', () => { - const mockUseUpdateUserProfile = jest.fn(); - const mockGetSpaceDarkModeValue = jest.fn(); +const mockUseUpdateUserProfile = jest.fn(); +jest.mock('@kbn/user-profile-components', () => { + const original = jest.requireActual('@kbn/user-profile-components'); + return { + ...original, + useUpdateUserProfile: () => mockUseUpdateUserProfile(), + }; +}); + +describe('ThemeDarkModeToggle', () => { it('renders correctly and toggles dark mode', () => { - const security = { - ...securityMock.createStart(), - hooks: { useUpdateUserProfile: mockUseUpdateUserProfile }, - }; - const { uiSettings } = coreMock.createStart(); + const security = securityMock.createStart(); + const core = coreMock.createStart(); const mockUpdate = jest.fn(); mockUseUpdateUserProfile.mockReturnValue({ @@ -31,10 +35,8 @@ describe('ThemDarkModeToggle', () => { update: mockUpdate, }); - mockGetSpaceDarkModeValue.mockReturnValue(false); - const { getByTestId, rerender } = render( - + ); const toggleSwitch = getByTestId('darkModeToggleSwitch'); @@ -49,7 +51,7 @@ describe('ThemDarkModeToggle', () => { }); // Rerender the component to apply the new props - rerender(); + rerender(); fireEvent.click(toggleSwitch); expect(mockUpdate).toHaveBeenLastCalledWith({ userSettings: { darkMode: 'light' } }); diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/theme_darkmode_toggle.tsx b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/theme_darkmode_toggle.tsx index 3f85c2ed63a76..20085172b2c68 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/theme_darkmode_toggle.tsx +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/theme_darkmode_toggle.tsx @@ -17,19 +17,30 @@ import { import { i18n } from '@kbn/i18n'; import type { SecurityPluginStart } from '@kbn/security-plugin/public'; import { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; +import { UserProfilesKibanaProvider } from '@kbn/user-profile-components'; +import { CoreStart } from '@kbn/core-lifecycle-browser'; +import { toMountPoint } from '@kbn/kibana-react-plugin/public'; + import { useThemeDarkmodeToggle } from './theme_darkmode_hook'; interface Props { - uiSettingsClient: IUiSettingsClient; security: SecurityPluginStart; + core: CoreStart; } -export const ThemDarkModeToggle = ({ security, uiSettingsClient }: Props) => { +export const ThemeDarkModeToggle = ({ security, core }: Props) => { + return ( + + + + ); +}; + +function ThemeDarkModeToggleUi({ uiSettingsClient }: { uiSettingsClient: IUiSettingsClient }) { const toggleTextSwitchId = useGeneratedHtmlId({ prefix: 'toggleTextSwitch' }); const { euiTheme } = useEuiTheme(); const { isVisible, toggle, isDarkModeOn, colorScheme } = useThemeDarkmodeToggle({ - security, uiSettingsClient, }); @@ -77,4 +88,4 @@ export const ThemDarkModeToggle = ({ security, uiSettingsClient }: Props) => { ); -}; +} diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/user_menu_links.tsx b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/user_menu_links.tsx index 1eae5d6ed0c58..16ffa32360f25 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/user_menu_links.tsx +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/user_menu_links.tsx @@ -9,17 +9,17 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import type { CloudStart } from '@kbn/cloud-plugin/public'; import type { SecurityPluginStart, UserMenuLink } from '@kbn/security-plugin/public'; -import { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; -import { ThemDarkModeToggle } from './theme_darkmode_toggle'; +import type { CoreStart } from '@kbn/core/public'; +import { ThemeDarkModeToggle } from './theme_darkmode_toggle'; export const createUserMenuLinks = ({ + core, cloud, security, - uiSettingsClient, }: { + core: CoreStart; cloud: CloudStart; security: SecurityPluginStart; - uiSettingsClient: IUiSettingsClient; }): UserMenuLink[] => { const { profileUrl, billingUrl, organizationUrl } = cloud; @@ -60,7 +60,7 @@ export const createUserMenuLinks = ({ } userMenuLinks.push({ - content: , + content: , order: 400, label: '', iconType: '', diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.tsx b/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.tsx index 7ee3f0969251d..38b568791b70b 100755 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.tsx +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.tsx @@ -44,11 +44,9 @@ export class CloudLinksPlugin } if (security) { maybeAddCloudLinks({ + core, security, - chrome: core.chrome, cloud, - docLinks: core.docLinks, - uiSettingsClient: core.uiSettings, }); } } diff --git a/x-pack/plugins/cloud_integrations/cloud_links/tsconfig.json b/x-pack/plugins/cloud_integrations/cloud_links/tsconfig.json index 0dfa7ce42858d..f1a67895cdd5e 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/tsconfig.json +++ b/x-pack/plugins/cloud_integrations/cloud_links/tsconfig.json @@ -20,6 +20,9 @@ "@kbn/core-chrome-browser", "@kbn/core-doc-links-browser", "@kbn/core-ui-settings-browser", + "@kbn/user-profile-components", + "@kbn/core-lifecycle-browser", + "@kbn/kibana-react-plugin", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/security/common/index.ts b/x-pack/plugins/security/common/index.ts index f7ee13c610a45..c547833949ded 100644 --- a/x-pack/plugins/security/common/index.ts +++ b/x-pack/plugins/security/common/index.ts @@ -23,7 +23,6 @@ export type { UserProfileWithSecurity, UserProfileData, UserProfileLabels, - UserProfileAvatarData, UserProfileUserInfoWithSecurity, ApiKey, UserRealm, diff --git a/x-pack/plugins/security/common/model/index.ts b/x-pack/plugins/security/common/model/index.ts index 822d6036efc06..c8505a644503f 100644 --- a/x-pack/plugins/security/common/model/index.ts +++ b/x-pack/plugins/security/common/model/index.ts @@ -22,7 +22,6 @@ export type { UserProfileData, UserProfileLabels, UserProfileUserInfoWithSecurity, - UserProfileAvatarData, } from './user_profile'; export { getUserAvatarColor, diff --git a/x-pack/plugins/security/common/model/user_profile.ts b/x-pack/plugins/security/common/model/user_profile.ts index c4dd6addd51fc..152b0d0266bbe 100644 --- a/x-pack/plugins/security/common/model/user_profile.ts +++ b/x-pack/plugins/security/common/model/user_profile.ts @@ -7,6 +7,8 @@ import { VISUALIZATION_COLORS } from '@elastic/eui'; +import type { UserProfileAvatarData } from '@kbn/user-profile-components'; + import type { AuthenticatedUser } from './authenticated_user'; import { getUserDisplayName } from './user'; @@ -72,33 +74,6 @@ export type UserProfileData = Record; */ export type UserProfileLabels = Record; -/** - * Avatar stored in user profile. - */ -export interface UserProfileAvatarData { - /** - * Optional initials (two letters) of the user to use as avatar if avatar picture isn't specified. - */ - initials?: string; - /** - * Background color of the avatar when initials are used. - */ - color?: string; - /** - * Base64 data URL for the user avatar image. - */ - imageUrl?: string | null; -} - -export type DarkModeValue = '' | 'dark' | 'light'; - -/** - * User settings stored in the data object of the User Profile - */ -export interface UserSettingsData { - darkMode?: DarkModeValue; -} - /** * Extended user information returned in user profile (both basic and security related properties). */ diff --git a/x-pack/plugins/security/public/account_management/account_management_app.tsx b/x-pack/plugins/security/public/account_management/account_management_app.tsx index 29722c10ea84d..a5b98d66d46ff 100644 --- a/x-pack/plugins/security/public/account_management/account_management_app.tsx +++ b/x-pack/plugins/security/public/account_management/account_management_app.tsx @@ -21,8 +21,13 @@ import type { import { AppNavLinkStatus } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import { I18nProvider } from '@kbn/i18n-react'; -import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import { + KibanaContextProvider, + KibanaThemeProvider, + toMountPoint, +} from '@kbn/kibana-react-plugin/public'; import { Router } from '@kbn/shared-ux-router'; +import { UserProfilesKibanaProvider } from '@kbn/user-profile-components'; import type { AuthenticationServiceSetup } from '../authentication'; import type { SecurityApiClients } from '../components'; @@ -96,7 +101,17 @@ export const Providers: FunctionComponent = ({ - {children} + + + {children} + + diff --git a/x-pack/plugins/security/public/account_management/index.ts b/x-pack/plugins/security/public/account_management/index.ts index eca7287537318..e1a4957aa71e7 100644 --- a/x-pack/plugins/security/public/account_management/index.ts +++ b/x-pack/plugins/security/public/account_management/index.ts @@ -11,5 +11,4 @@ export type { UserProfileBulkGetParams, UserProfileGetCurrentParams, UserProfileSuggestParams, - UpdateUserProfileHook, } from './user_profile'; diff --git a/x-pack/plugins/security/public/account_management/user_profile/index.ts b/x-pack/plugins/security/public/account_management/user_profile/index.ts index 93a1c7d04d315..ed34d7d4a4339 100644 --- a/x-pack/plugins/security/public/account_management/user_profile/index.ts +++ b/x-pack/plugins/security/public/account_management/user_profile/index.ts @@ -13,5 +13,3 @@ export type { UserProfileBulkGetParams, UserProfileSuggestParams, } from './user_profile_api_client'; - -export type { UpdateUserProfileHook } from './use_update_user_profile'; diff --git a/x-pack/plugins/security/public/account_management/user_profile/use_update_user_profile.tsx b/x-pack/plugins/security/public/account_management/user_profile/use_update_user_profile.tsx deleted file mode 100644 index 2dafa61496fe8..0000000000000 --- a/x-pack/plugins/security/public/account_management/user_profile/use_update_user_profile.tsx +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import React, { useCallback, useRef, useState } from 'react'; -import useObservable from 'react-use/lib/useObservable'; - -import type { NotificationsStart, ToastInput, ToastOptions } from '@kbn/core/public'; -import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; - -import type { UserProfileData } from './user_profile'; -import type { UserProfileAPIClient } from './user_profile_api_client'; - -interface Deps { - apiClient: UserProfileAPIClient; - notifications: NotificationsStart; -} - -interface Props { - notificationSuccess?: { - /** Flag to indicate if a notification is shown after update. Default: `true` */ - enabled?: boolean; - /** Customize the title of the notification */ - title?: string; - /** Customize the "page reload needed" text of the notification */ - pageReloadText?: string; - }; - /** Predicate to indicate if the update requires a page reload */ - pageReloadChecker?: ( - previsous: UserProfileData | null | undefined, - next: UserProfileData - ) => boolean; -} - -export type UpdateUserProfileHook = (props?: Props) => { - /** Update the user profile */ - update: (data: UserProfileData) => void; - /** Handler to show a notification after the user profile has been updated */ - showSuccessNotification: (props: { isRefreshRequired: boolean }) => void; - /** Flag to indicate if currently updating */ - isLoading: boolean; - /** The current user profile data */ - userProfileData?: UserProfileData | null; -}; - -const i18nTexts = { - notificationSuccess: { - title: i18n.translate('xpack.security.accountManagement.userProfile.submitSuccessTitle', { - defaultMessage: 'Profile updated', - }), - pageReloadText: i18n.translate( - 'xpack.security.accountManagement.userProfile.requiresPageReloadToastDescription', - { - defaultMessage: 'One or more settings require you to reload the page to take effect.', - } - ), - }, -}; - -export const getUseUpdateUserProfile = ({ apiClient, notifications }: Deps) => { - const { userProfile$ } = apiClient; - - const useUpdateUserProfile = ({ notificationSuccess = {}, pageReloadChecker }: Props = {}) => { - const { - enabled: notificationSuccessEnabled = true, - title: notificationTitle = i18nTexts.notificationSuccess.title, - pageReloadText = i18nTexts.notificationSuccess.pageReloadText, - } = notificationSuccess; - const [isLoading, setIsLoading] = useState(false); - const userProfileData = useObservable(userProfile$); - // Keep a snapshot before updating the user profile so we can compare previous and updated values - const userProfileSnapshot = useRef(); - - const showSuccessNotification = useCallback( - ({ isRefreshRequired = false }: { isRefreshRequired?: boolean } = {}) => { - let successToastInput: ToastInput = { - title: notificationTitle, - }; - let successToastOptions: ToastOptions = {}; - - if (isRefreshRequired) { - successToastOptions = { - toastLifeTimeMs: 1000 * 60 * 5, - }; - - successToastInput = { - ...successToastInput, - text: toMountPoint( - - -

    {pageReloadText}

    - window.location.reload()} - data-test-subj="windowReloadButton" - > - {i18n.translate( - 'xpack.security.accountManagement.userProfile.requiresPageReloadToastButtonLabel', - { - defaultMessage: 'Reload page', - } - )} - -
    -
    - ), - }; - } - - notifications.toasts.addSuccess(successToastInput, successToastOptions); - }, - [notificationTitle, pageReloadText] - ); - - const onUserProfileUpdate = useCallback( - (updatedData: UserProfileData) => { - setIsLoading(false); - - if (notificationSuccessEnabled) { - const isRefreshRequired = pageReloadChecker?.(userProfileSnapshot.current, updatedData); - showSuccessNotification({ isRefreshRequired }); - } - }, - [notificationSuccessEnabled, showSuccessNotification, pageReloadChecker] - ); - - const update = useCallback( - (udpatedData: D) => { - userProfileSnapshot.current = userProfileData; - setIsLoading(true); - return apiClient.update(udpatedData).then(() => onUserProfileUpdate(udpatedData)); - }, - [onUserProfileUpdate, userProfileData] - ); - - return { - update, - showSuccessNotification, - userProfileData, - isLoading, - }; - }; - - return useUpdateUserProfile; -}; diff --git a/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx b/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx index 2632f73e99d07..a6227baee4061 100644 --- a/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx +++ b/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx @@ -39,7 +39,8 @@ import type { CoreStart, IUiSettingsClient } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { UserAvatar } from '@kbn/user-profile-components'; +import type { DarkModeValue, UserProfileData } from '@kbn/user-profile-components'; +import { UserAvatar, useUpdateUserProfile } from '@kbn/user-profile-components'; import type { AuthenticatedUser } from '../../../common'; import { @@ -48,11 +49,6 @@ import { getUserAvatarColor, getUserAvatarInitials, } from '../../../common/model'; -import type { - DarkModeValue, - UserProfileAvatarData, - UserSettingsData, -} from '../../../common/model/user_profile'; import { useSecurityApiClients } from '../../components'; import { Breadcrumb } from '../../components/breadcrumb'; import { @@ -65,15 +61,8 @@ import { FormLabel } from '../../components/form_label'; import { FormRow, OptionalText } from '../../components/form_row'; import { ChangePasswordModal } from '../../management/users/edit_user/change_password_modal'; import { isUserReserved } from '../../management/users/user_utils'; -import { getUseUpdateUserProfile } from './use_update_user_profile'; import { createImageHandler, getRandomColor, IMAGE_FILE_TYPES, VALID_HEX_COLOR } from './utils'; -export interface UserProfileData { - avatar?: UserProfileAvatarData; - userSettings?: UserSettingsData; - [key: string]: unknown; -} - export interface UserProfileProps { user: AuthenticatedUser; data?: UserProfileData; @@ -833,12 +822,11 @@ export const UserProfile: FunctionComponent = ({ user, data }) export function useUserProfileForm({ user, data }: UserProfileProps) { const { services } = useKibana(); - const { userProfiles, users } = useSecurityApiClients(); + const { users } = useSecurityApiClients(); - const { update, showSuccessNotification } = getUseUpdateUserProfile({ - apiClient: userProfiles, - notifications: services.notifications, - })({ notificationSuccess: { enabled: false } }); + const { update, showSuccessNotification } = useUpdateUserProfile({ + notificationSuccess: { enabled: false }, + }); const [initialValues, resetInitialValues] = useState({ user: { diff --git a/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts b/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts index 4b992f616ca14..4760aa15ab0b3 100644 --- a/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts +++ b/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts @@ -10,9 +10,9 @@ import type { Observable } from 'rxjs'; import { BehaviorSubject, Subject } from 'rxjs'; import type { HttpStart } from '@kbn/core/public'; +import type { UserProfileData } from '@kbn/user-profile-components'; import type { GetUserProfileResponse, UserProfile } from '../../../common'; -import type { UserProfileData } from './user_profile'; /** * Parameters for the get user profile for the current user API. diff --git a/x-pack/plugins/security/public/index.ts b/x-pack/plugins/security/public/index.ts index b51bb3d25092e..209bc5ff576b6 100644 --- a/x-pack/plugins/security/public/index.ts +++ b/x-pack/plugins/security/public/index.ts @@ -24,7 +24,6 @@ export type { UserProfileBulkGetParams, UserProfileGetCurrentParams, UserProfileSuggestParams, - UpdateUserProfileHook, } from './account_management'; export type { AuthenticationServiceStart, AuthenticationServiceSetup } from './authentication'; diff --git a/x-pack/plugins/security/public/mocks.ts b/x-pack/plugins/security/public/mocks.ts index f0081307ef33f..8a9232869b430 100644 --- a/x-pack/plugins/security/public/mocks.ts +++ b/x-pack/plugins/security/public/mocks.ts @@ -32,9 +32,6 @@ function createStartMock() { userProfile$: of({}), }, uiApi: getUiApiMock.createStart(), - hooks: { - useUpdateUserProfile: jest.fn(), - }, }; } diff --git a/x-pack/plugins/security/public/nav_control/nav_control_component.tsx b/x-pack/plugins/security/public/nav_control/nav_control_component.tsx index 4a5e8ad545d64..13bcb3bcb4341 100644 --- a/x-pack/plugins/security/public/nav_control/nav_control_component.tsx +++ b/x-pack/plugins/security/public/nav_control/nav_control_component.tsx @@ -22,9 +22,8 @@ import type { Observable } from 'rxjs'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { UserAvatar } from '@kbn/user-profile-components'; +import { UserAvatar, type UserProfileAvatarData } from '@kbn/user-profile-components'; -import type { UserProfileAvatarData } from '../../common'; import { getUserDisplayName, isUserAnonymous } from '../../common/model'; import { useCurrentUser, useUserProfile } from '../components'; diff --git a/x-pack/plugins/security/public/plugin.test.tsx b/x-pack/plugins/security/public/plugin.test.tsx index 87ce15a19202d..fdab78a1f91d0 100644 --- a/x-pack/plugins/security/public/plugin.test.tsx +++ b/x-pack/plugins/security/public/plugin.test.tsx @@ -96,9 +96,6 @@ describe('Security Plugin', () => { "areAPIKeysEnabled": [Function], "getCurrentUser": [Function], }, - "hooks": Object { - "useUpdateUserProfile": [Function], - }, "navControlService": Object { "addUserMenuLinks": [Function], "getUserMenuLinks$": [Function], diff --git a/x-pack/plugins/security/public/plugin.tsx b/x-pack/plugins/security/public/plugin.tsx index e8c2c13ab0eb6..49c0a14e2fd9c 100644 --- a/x-pack/plugins/security/public/plugin.tsx +++ b/x-pack/plugins/security/public/plugin.tsx @@ -24,9 +24,7 @@ import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import type { SecurityLicense } from '../common/licensing'; import { SecurityLicenseService } from '../common/licensing'; -import type { UpdateUserProfileHook } from './account_management'; import { accountManagementApp, UserProfileAPIClient } from './account_management'; -import { getUseUpdateUserProfile } from './account_management/user_profile/use_update_user_profile'; import { AnalyticsService } from './analytics'; import { AnonymousAccessService } from './anonymous_access'; import type { AuthenticationServiceSetup, AuthenticationServiceStart } from './authentication'; @@ -213,12 +211,6 @@ export class SecurityPlugin ), userProfile$: this.securityApiClients.userProfiles.userProfile$, }, - hooks: { - useUpdateUserProfile: getUseUpdateUserProfile({ - apiClient: this.securityApiClients.userProfiles, - notifications: core.notifications, - }), - }, }; } @@ -263,13 +255,6 @@ export interface SecurityPluginStart { 'getCurrent' | 'bulkGet' | 'suggest' | 'update' | 'userProfile$' >; - /** - * A set of hooks to work with Kibana user profiles - */ - hooks: { - useUpdateUserProfile: UpdateUserProfileHook; - }; - /** * Exposes UI components that will be loaded asynchronously. * @deprecated diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 11f22770bec5f..f70caee66aec9 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -29231,10 +29231,7 @@ "xpack.security.accountManagement.userProfile.passwordLabel": "Mot de passe", "xpack.security.accountManagement.userProfile.prepopulatedImageUrlPromptText": "Sélectionner ou glisser-déposer une image de remplacement", "xpack.security.accountManagement.userProfile.randomizeButton": "Randomiser", - "xpack.security.accountManagement.userProfile.requiresPageReloadToastButtonLabel": "Actualiser la page", - "xpack.security.accountManagement.userProfile.requiresPageReloadToastDescription": "Un ou plusieurs paramètres nécessitent d’actualiser la page pour pouvoir prendre effet.", "xpack.security.accountManagement.userProfile.submitErrorTitle": "Impossible de mettre à jour le profil", - "xpack.security.accountManagement.userProfile.submitSuccessTitle": "Profil mis à jour", "xpack.security.accountManagement.userProfile.themeFormGroupDescription": "Sélectionnez l'apparence de votre interface.", "xpack.security.accountManagement.userProfile.title": "Profil", "xpack.security.accountManagement.userProfile.usernameHelpText": "Le nom de l'utilisateur ne peut pas être modifié après la création du compte.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 15960dbd920ed..ca71e8c833cb5 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -29230,10 +29230,7 @@ "xpack.security.accountManagement.userProfile.passwordLabel": "パスワード", "xpack.security.accountManagement.userProfile.prepopulatedImageUrlPromptText": "置換画像を選択するかドラッグアンドドロップします", "xpack.security.accountManagement.userProfile.randomizeButton": "ランダム化", - "xpack.security.accountManagement.userProfile.requiresPageReloadToastButtonLabel": "ページを再読み込み", - "xpack.security.accountManagement.userProfile.requiresPageReloadToastDescription": "設定を有効にするためにページの再読み込みが必要です。", "xpack.security.accountManagement.userProfile.submitErrorTitle": "プロファイルを更新できませんでした", - "xpack.security.accountManagement.userProfile.submitSuccessTitle": "プロファイルが更新されました", "xpack.security.accountManagement.userProfile.themeFormGroupDescription": "インターフェースの表示を選択します。", "xpack.security.accountManagement.userProfile.title": "プロフィール", "xpack.security.accountManagement.userProfile.usernameHelpText": "アカウントの作成後は、ユーザー名を変更できません。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 0cff43087c67f..ef71636689383 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -29226,10 +29226,7 @@ "xpack.security.accountManagement.userProfile.passwordLabel": "密码", "xpack.security.accountManagement.userProfile.prepopulatedImageUrlPromptText": "选择或拖放替换图像", "xpack.security.accountManagement.userProfile.randomizeButton": "随机化", - "xpack.security.accountManagement.userProfile.requiresPageReloadToastButtonLabel": "重新加载页面", - "xpack.security.accountManagement.userProfile.requiresPageReloadToastDescription": "一个或多个设置需要您重新加载页面才能生效。", "xpack.security.accountManagement.userProfile.submitErrorTitle": "无法更新配置文件", - "xpack.security.accountManagement.userProfile.submitSuccessTitle": "配置文件已更新", "xpack.security.accountManagement.userProfile.themeFormGroupDescription": "选择您界面的外观。", "xpack.security.accountManagement.userProfile.title": "配置文件", "xpack.security.accountManagement.userProfile.usernameHelpText": "创建帐户后无法更改用户名。", diff --git a/x-pack/test/cases_api_integration/common/lib/api/user_profiles.ts b/x-pack/test/cases_api_integration/common/lib/api/user_profiles.ts index 25c7f7a7a9ba4..bc78feab4070c 100644 --- a/x-pack/test/cases_api_integration/common/lib/api/user_profiles.ts +++ b/x-pack/test/cases_api_integration/common/lib/api/user_profiles.ts @@ -10,8 +10,11 @@ import { parse as parseCookie, Cookie } from 'tough-cookie'; import { INTERNAL_SUGGEST_USER_PROFILES_URL } from '@kbn/cases-plugin/common/constants'; import { UserProfileService } from '@kbn/cases-plugin/server/services'; -import { UserProfileAvatarData } from '@kbn/security-plugin/common'; -import { UserProfile, UserProfileWithAvatar } from '@kbn/user-profile-components'; +import type { + UserProfile, + UserProfileAvatarData, + UserProfileWithAvatar, +} from '@kbn/user-profile-components'; import { SuggestUserProfilesRequest } from '@kbn/cases-plugin/common/types/api'; import { superUser } from '../authentication/users'; import { User } from '../authentication/types'; From 9d6ebdda4e630f0973ab6ece2803a878cea09227 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 9 Aug 2023 18:21:37 +0200 Subject: [PATCH 16/22] [Synthetics] Fix 404 not found monitor view (#163501) --- .../synthetics/server/routes/monitor_cruds/get_monitor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_monitor.ts b/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_monitor.ts index 16d63c60c4e1b..770fb102c5369 100644 --- a/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_monitor.ts +++ b/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_monitor.ts @@ -59,7 +59,7 @@ export const getSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => ({ const encryptedSavedObjectsClient = encryptedSavedObjects.getClient(); - return getSyntheticsMonitor({ + return await getSyntheticsMonitor({ monitorId, encryptedSavedObjectsClient, savedObjectsClient, From b9fd22bd11c69b641e418c0a9832b195f665f4d0 Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Wed, 9 Aug 2023 18:36:07 +0200 Subject: [PATCH 17/22] [Lens] Top values hints for time series dimensions when counter/gauges fields are used (#162916) ## Summary Fixes #154832 This PR is a first attempt to provide a visual feedback to users while configuring a visualization that use a time series metric, showing a new category in the field picker that highlights time series dimensions by which the gauge/counter are mapped against. Current idea: * Works with XY and Heatmap visualizations only * Works only for Breakdown (XY) and Y axis (Heatmap) only * Top values on the horizontal axis for both visualizations won't show the new field category * The feature is enabled only when a metric using a time series metric field (like gauge or counter) is detected in the configuration, otherwise the category is hidden. * The feature is disabled for multi terms - it means that just the group is hidden, no impact on the actual field * Fields for this group are taken from both `Available` and `Empty` fields but the rendering styles for the empty case is retained. Screenshot 2023-08-01 at 17 52 38 Empty field but within the Time series dimension: Screenshot 2023-08-08 at 16 29 17 While the actual implementation of the ES aggs is not leveraging yet this information, this is still useful to indicate to the user which dimension the index/dataView mapping author thought it makes sense that metric. With #152537 also the aggregation request will benefit from this. ### Checklist Delete any items that are not applicable to this PR. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Stratoula Kalafateli --- .../public/data_views_service/loader.test.ts | 59 +++++++++++ .../lens/public/data_views_service/loader.ts | 4 +- .../dimension_panel/field_input.test.tsx | 97 +++++++++++++++++-- .../dimension_panel/field_input.tsx | 7 ++ .../dimension_panel/field_select.tsx | 52 ++++++++-- .../dimension_panel/reference_editor.tsx | 1 + .../public/datasources/form_based/mocks.ts | 12 +++ .../definitions/terms/field_inputs.tsx | 3 + .../operations/definitions/terms/index.tsx | 7 ++ .../datasources/form_based/pure_utils.ts | 29 +++++- x-pack/plugins/lens/public/types.ts | 1 + .../heatmap/visualization.test.ts | 3 + .../visualizations/heatmap/visualization.tsx | 1 + .../visualizations/xy/visualization.tsx | 1 + .../test/functional/apps/lens/group4/tsdb.ts | 44 +++++++++ 15 files changed, 306 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/lens/public/data_views_service/loader.test.ts b/x-pack/plugins/lens/public/data_views_service/loader.test.ts index e7e2bab166a70..f91d236986b11 100644 --- a/x-pack/plugins/lens/public/data_views_service/loader.test.ts +++ b/x-pack/plugins/lens/public/data_views_service/loader.test.ts @@ -159,6 +159,65 @@ describe('loader', () => { expect(cache.foo.getFieldByName('timestamp')!.meta).toEqual(true); }); + it('should move over any time series meta data', async () => { + const cache = await loadIndexPatterns({ + cache: {}, + patterns: ['foo'], + dataViews: { + get: jest.fn(async () => ({ + id: 'foo', + title: 'Foo index', + metaFields: ['timestamp'], + isPersisted: () => true, + toSpec: () => ({}), + typeMeta: {}, + fields: [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes_counter', + displayName: 'bytes_counter', + type: 'number', + aggregatable: true, + searchable: true, + timeSeriesMetric: 'counter', + }, + { + name: 'bytes_gauge', + displayName: 'bytes_gauge', + type: 'number', + aggregatable: true, + searchable: true, + timeSeriesMetric: 'gauge', + }, + { + name: 'dimension', + displayName: 'dimension', + type: 'string', + aggregatable: true, + searchable: true, + timeSeriesDimension: true, + }, + ], + })), + getIdsWithTitle: jest.fn(async () => ({ + id: 'foo', + title: 'Foo index', + })), + create: jest.fn(), + } as unknown as Pick, + }); + + expect(cache.foo.getFieldByName('bytes_counter')!.timeSeriesMetric).toEqual('counter'); + expect(cache.foo.getFieldByName('bytes_gauge')!.timeSeriesMetric).toEqual('gauge'); + expect(cache.foo.getFieldByName('dimension')!.timeSeriesDimension).toEqual(true); + }); + it('should call the refresh callback when loading new indexpatterns', async () => { const onIndexPatternRefresh = jest.fn(); await loadIndexPatterns({ diff --git a/x-pack/plugins/lens/public/data_views_service/loader.ts b/x-pack/plugins/lens/public/data_views_service/loader.ts index f38a84cc60b48..784c97d832e34 100644 --- a/x-pack/plugins/lens/public/data_views_service/loader.ts +++ b/x-pack/plugins/lens/public/data_views_service/loader.ts @@ -29,6 +29,7 @@ export function convertDataViewIntoLensIndexPattern( dataView: DataView, restrictionRemapper: (name: string) => string = onRestrictionMapping ): IndexPattern { + const metaKeys = new Set(dataView.metaFields); const newFields = dataView.fields .filter(isFieldLensCompatible) .map((field): IndexPatternField => { @@ -40,13 +41,14 @@ export function convertDataViewIntoLensIndexPattern( aggregatable: field.aggregatable, filterable: field.filterable, searchable: field.searchable, - meta: dataView.metaFields.includes(field.name), + meta: metaKeys.has(field.name), esTypes: field.esTypes, scripted: field.scripted, isMapped: field.isMapped, customLabel: field.customLabel, runtimeField: field.runtimeField, runtime: Boolean(field.runtimeField), + timeSeriesDimension: field.timeSeriesDimension, timeSeriesMetric: field.timeSeriesMetric, timeSeriesRollup: field.isRolledUpField, partiallyApplicableFunctions: field.isRolledUpField diff --git a/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/field_input.test.tsx b/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/field_input.test.tsx index 1a22e34e0a3ec..d307e0eb094a2 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/field_input.test.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/field_input.test.tsx @@ -17,12 +17,15 @@ import { FieldBasedIndexPatternColumn, termsOperation, staticValueOperation, + minOperation, } from '../operations/definitions'; import { FieldInput, getErrorMessage } from './field_input'; -import { createMockedIndexPattern } from '../mocks'; +import { createMockedIndexPattern, createMockedIndexPatternWithAdditionalFields } from '../mocks'; import { getOperationSupportMatrix } from '.'; import { GenericIndexPatternColumn, FormBasedLayer, FormBasedPrivateState } from '../types'; import { ReferenceBasedIndexPatternColumn } from '../operations/definitions/column_types'; +import { FieldSelect } from './field_select'; +import { IndexPattern, VisualizationDimensionGroupConfig } from '../../../types'; jest.mock('../operations/layer_helpers', () => { const original = jest.requireActual('../operations/layer_helpers'); @@ -41,7 +44,7 @@ const defaultProps = { incompleteField: null, incompleteOperation: undefined, incompleteParams: {}, - dimensionGroups: [], + dimensionGroups: [] as VisualizationDimensionGroupConfig[], groupId: 'any', operationDefinitionMap: { terms: termsOperation, @@ -49,6 +52,7 @@ const defaultProps = { count: countOperation, differences: derivativeOperation, staticValue: staticValueOperation, + min: minOperation, } as unknown as Record, }; @@ -102,9 +106,12 @@ function getCountOperationColumn(): GenericIndexPatternColumn { operationType: 'count', }; } -function getLayer(col1: GenericIndexPatternColumn = getStringBasedOperationColumn()) { +function getLayer( + col1: GenericIndexPatternColumn = getStringBasedOperationColumn(), + indexPattern?: IndexPattern +) { return { - indexPatternId: '1', + indexPatternId: defaultProps.indexPattern.id, columnOrder: ['col1', 'col2'], columns: { col1, @@ -112,7 +119,11 @@ function getLayer(col1: GenericIndexPatternColumn = getStringBasedOperationColum }, }; } -function getDefaultOperationSupportMatrix(layer: FormBasedLayer, columnId: string) { +function getDefaultOperationSupportMatrix( + layer: FormBasedLayer, + columnId: string, + indexPattern?: IndexPattern +) { return getOperationSupportMatrix({ state: { layers: { layer1: layer }, @@ -121,7 +132,7 @@ function getDefaultOperationSupportMatrix(layer: FormBasedLayer, columnId: strin filterOperations: () => true, columnId, indexPatterns: { - [defaultProps.indexPattern.id]: defaultProps.indexPattern, + [defaultProps.indexPattern.id]: indexPattern ?? defaultProps.indexPattern, }, }); } @@ -421,6 +432,80 @@ describe('FieldInput', () => { expect(onDeleteColumn).toHaveBeenCalled(); expect(updateLayerSpy).not.toHaveBeenCalled(); }); + + describe('time series group', () => { + function getLayerWithTSDBMetric() { + const layer = getLayer(); + layer.columns.col2 = { + label: 'Min of TSDB counter', + dataType: 'number', + isBucketed: false, + sourceField: 'bytes_counter', + operationType: 'min', + }; + return layer; + } + it('should not render the time dimension category if it has tsdb metric column but the group is not a breakdown', () => { + const updateLayerSpy = jest.fn(); + const layer = getLayerWithTSDBMetric(); + const operationSupportMatrix = getDefaultOperationSupportMatrix(layer, 'col1'); + const instance = mount( + + ); + + expect(instance.find(FieldSelect).prop('showTimeSeriesDimensions')).toBeFalsy(); + }); + + it('should render the time dimension category if it has tsdb metric column and the group is a breakdown one', () => { + const updateLayerSpy = jest.fn(); + const layer = getLayerWithTSDBMetric(); + const operationSupportMatrix = getDefaultOperationSupportMatrix(layer, 'col1'); + const instance = mount( + + ); + + expect(instance.find(FieldSelect).prop('showTimeSeriesDimensions')).toBeTruthy(); + }); + }); }); describe('getErrorMessage', () => { diff --git a/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/field_input.tsx b/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/field_input.tsx index 462cd0b546f22..5120c89c37b30 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/field_input.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/field_input.tsx @@ -16,6 +16,7 @@ import type { GenericIndexPatternColumn, } from '../operations/definitions'; import type { FieldBasedIndexPatternColumn } from '../operations/definitions/column_types'; +import { shouldShowTimeSeriesOption } from '../pure_utils'; export function FieldInput({ layer, @@ -83,6 +84,12 @@ export function FieldInput({ }) ); }} + showTimeSeriesDimensions={shouldShowTimeSeriesOption( + layer, + indexPattern, + groupId, + dimensionGroups + )} /> ); diff --git a/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/field_select.tsx b/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/field_select.tsx index cbfafbfbfd2c9..909bc64781399 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/field_select.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/field_select.tsx @@ -33,6 +33,7 @@ export interface FieldSelectProps extends EuiComboBoxProps { @@ -66,7 +68,15 @@ export function FieldSelect({ return fieldContainsData(fieldName, currentIndexPattern, hasFieldData); } - function fieldNamesToOptions(items: string[]) { + interface FieldOption { + label: string; + value: { type: 'field'; field: string; dataType: string | undefined; operationType: string }; + exists: boolean; + compatible: number; + 'data-test-subj': string; + } + + function fieldNamesToOptions(items: string[]): FieldOption[] { return items .filter((field) => currentIndexPattern.getFieldByName(field)?.displayName) .map((field) => { @@ -75,9 +85,9 @@ export function FieldSelect({ const exists = containsData(field); const fieldInstance = currentIndexPattern.getFieldByName(field); return { - label: currentIndexPattern.getFieldByName(field)?.displayName, + label: currentIndexPattern.getFieldByName(field)?.displayName ?? field, value: { - type: 'field', + type: 'field' as const, field, dataType: fieldInstance ? getFieldType(fieldInstance) : undefined, // Use the operation directly, or choose the first compatible operation. @@ -102,21 +112,47 @@ export function FieldSelect({ ); const [availableFields, emptyFields] = partition(nonMetaFields, containsData); - const constructFieldsOptions = (fieldsArr: string[], label: string) => + const constructFieldsOptions = ( + fieldsArr: string[], + label: string + ): { label: string; options: FieldOption[] } | false => fieldsArr.length > 0 && { label, options: fieldNamesToOptions(fieldsArr), }; - const availableFieldsOptions = constructFieldsOptions( + const isTimeSeriesFields = (field: string) => { + return ( + showTimeSeriesDimensions && currentIndexPattern.getFieldByName(field)?.timeSeriesDimension + ); + }; + + const [availableTimeSeriesFields, availableNonTimeseriesFields] = partition( availableFields, + isTimeSeriesFields + ); + const [emptyTimeSeriesFields, emptyNonTimeseriesFields] = partition( + emptyFields, + isTimeSeriesFields + ); + + const timeSeriesFieldsOptions = constructFieldsOptions( + // This group includes both available and empty fields + availableTimeSeriesFields.concat(emptyTimeSeriesFields), + i18n.translate('xpack.lens.indexPattern.timeSeriesFieldsLabel', { + defaultMessage: 'Time series dimensions', + }) + ); + + const availableFieldsOptions = constructFieldsOptions( + availableNonTimeseriesFields, i18n.translate('xpack.lens.indexPattern.availableFieldsLabel', { defaultMessage: 'Available fields', }) ); const emptyFieldsOptions = constructFieldsOptions( - emptyFields, + emptyNonTimeseriesFields, i18n.translate('xpack.lens.indexPattern.emptyFieldsLabel', { defaultMessage: 'Empty fields', }) @@ -131,17 +167,19 @@ export function FieldSelect({ return [ ...fieldNamesToOptions(specialFields), + timeSeriesFieldsOptions, availableFieldsOptions, emptyFieldsOptions, metaFieldsOptions, ].filter(Boolean); }, [ + operationByField, incompleteOperation, selectedOperationType, currentIndexPattern, - operationByField, hasFieldData, markAllFieldsCompatible, + showTimeSeriesDimensions, ]); return ( diff --git a/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/reference_editor.tsx b/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/reference_editor.tsx index 28810825dd7a0..66a01daae0581 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/reference_editor.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/dimension_panel/reference_editor.tsx @@ -317,6 +317,7 @@ export const ReferenceEditor = (props: ReferenceEditorProps) => { markAllFieldsCompatible={selectionStyle === 'field'} onDeleteColumn={onDeleteColumn} onChoose={onChooseField} + showTimeSeriesDimensions={false} /> ) : null} diff --git a/x-pack/plugins/lens/public/datasources/form_based/mocks.ts b/x-pack/plugins/lens/public/datasources/form_based/mocks.ts index c01495f1993e4..fcefa97ecd4b1 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/mocks.ts +++ b/x-pack/plugins/lens/public/datasources/form_based/mocks.ts @@ -216,3 +216,15 @@ export const createMockedIndexPatternWithoutType = ( getFieldByName: getFieldByNameFactory(filteredFields), }; }; + +export const createMockedIndexPatternWithAdditionalFields = ( + newFields: IndexPatternField[] +): IndexPattern => { + const { fields, ...otherIndexPatternProps } = createMockedIndexPattern(); + const completeFields = fields.concat(newFields); + return { + ...otherIndexPatternProps, + fields: completeFields, + getFieldByName: getFieldByNameFactory(completeFields), + }; +}; diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/field_inputs.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/field_inputs.tsx index 72941739b24ed..428747b6cda75 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/field_inputs.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/field_inputs.tsx @@ -30,6 +30,7 @@ export interface FieldInputsProps { invalidFields?: string[]; operationSupportMatrix: Pick; onChange: (newValues: string[]) => void; + showTimeSeriesDimensions: boolean; } interface WrappedValue { @@ -50,6 +51,7 @@ export function FieldInputs({ indexPattern, operationSupportMatrix, invalidFields, + showTimeSeriesDimensions, }: FieldInputsProps) { const onChangeWrapped = useCallback( (values: WrappedValue[]) => @@ -165,6 +167,7 @@ export function FieldInputs({ data-test-subj={ localValues.length !== 1 ? `indexPattern-dimension-field-${index}` : undefined } + showTimeSeriesDimensions={localValues.length < 2 && showTimeSeriesDimensions} /> ); diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/index.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/index.tsx index 504abd15955e0..4aafe38ea39ee 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/index.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/index.tsx @@ -53,6 +53,7 @@ import { supportedTypes, } from './constants'; import { IncludeExcludeRow } from './include_exclude_options'; +import { shouldShowTimeSeriesOption } from '../../../pure_utils'; export function supportsRarityRanking(field?: IndexPatternField) { // these es field types can't be sorted by rarity @@ -591,6 +592,12 @@ export const termsOperation: OperationDefinition< operationSupportMatrix={operationSupportMatrix} onChange={onFieldSelectChange} invalidFields={invalidFields} + showTimeSeriesDimensions={shouldShowTimeSeriesOption( + layer, + indexPattern, + groupId, + dimensionGroups + )} /> ); diff --git a/x-pack/plugins/lens/public/datasources/form_based/pure_utils.ts b/x-pack/plugins/lens/public/datasources/form_based/pure_utils.ts index b13fd50a45e73..256c1de51f832 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/pure_utils.ts +++ b/x-pack/plugins/lens/public/datasources/form_based/pure_utils.ts @@ -5,7 +5,12 @@ * 2.0. */ -import type { DataType, IndexPattern, IndexPatternField } from '../../types'; +import type { + DataType, + IndexPattern, + IndexPatternField, + VisualizationDimensionGroupConfig, +} from '../../types'; import type { FormBasedLayer } from './types'; import type { BaseIndexPatternColumn, @@ -26,6 +31,28 @@ export function hasField(column: BaseIndexPatternColumn): column is FieldBasedIn return 'sourceField' in column; } +export function shouldShowTimeSeriesOption( + layer: FormBasedLayer, + indexPattern: IndexPattern, + groupId: string, + dimensionGroups: VisualizationDimensionGroupConfig[] +) { + return Boolean( + dimensionGroups.find(({ groupId: id }) => groupId === id)?.isBreakdownDimension && + containsColumnWithTimeSeriesMetric(layer, indexPattern) + ); +} + +function containsColumnWithTimeSeriesMetric( + layer: FormBasedLayer, + indexPattern: IndexPattern +): boolean { + return Object.values(layer.columns).some( + (column) => + hasField(column) && indexPattern.getFieldByName(column.sourceField)?.timeSeriesMetric + ); +} + export function getFieldType(field: IndexPatternField) { if (field.timeSeriesMetric) { return field.timeSeriesMetric; diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 8b69929b4fb84..13651c3bc5e69 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -814,6 +814,7 @@ export type VisualizationDimensionGroupConfig = SharedDimensionProps & { supportStaticValue?: boolean; // used by text based datasource to restrict the field selection only to number fields for the metric dimensions isMetricDimension?: boolean; + isBreakdownDimension?: boolean; paramEditorCustomProps?: ParamEditorCustomProps; enableFormatSelector?: boolean; labels?: { buttonAriaLabel: string; buttonLabel: string }; diff --git a/x-pack/plugins/lens/public/visualizations/heatmap/visualization.test.ts b/x-pack/plugins/lens/public/visualizations/heatmap/visualization.test.ts index 596c334aeac9e..dc9202a4d7e92 100644 --- a/x-pack/plugins/lens/public/visualizations/heatmap/visualization.test.ts +++ b/x-pack/plugins/lens/public/visualizations/heatmap/visualization.test.ts @@ -150,6 +150,7 @@ describe('heatmap', () => { groupLabel: 'Vertical axis', accessors: [{ columnId: 'y-accessor' }], filterOperations: filterOperationsAxis, + isBreakdownDimension: true, supportsMoreColumns: false, requiredMinDimensionCount: 0, dataTestSubj: 'lnsHeatmap_yDimensionPanel', @@ -210,6 +211,7 @@ describe('heatmap', () => { accessors: [], filterOperations: filterOperationsAxis, supportsMoreColumns: true, + isBreakdownDimension: true, requiredMinDimensionCount: 0, dataTestSubj: 'lnsHeatmap_yDimensionPanel', }, @@ -267,6 +269,7 @@ describe('heatmap', () => { accessors: [{ columnId: 'y-accessor' }], filterOperations: filterOperationsAxis, supportsMoreColumns: false, + isBreakdownDimension: true, requiredMinDimensionCount: 0, dataTestSubj: 'lnsHeatmap_yDimensionPanel', }, diff --git a/x-pack/plugins/lens/public/visualizations/heatmap/visualization.tsx b/x-pack/plugins/lens/public/visualizations/heatmap/visualization.tsx index 654d69284718c..5d19c402a27e2 100644 --- a/x-pack/plugins/lens/public/visualizations/heatmap/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/heatmap/visualization.tsx @@ -197,6 +197,7 @@ export const getHeatmapVisualization = ({ filterOperations: filterOperationsAxis, supportsMoreColumns: !state.yAccessor, requiredMinDimensionCount: 0, + isBreakdownDimension: true, dataTestSubj: 'lnsHeatmap_yDimensionPanel', }, { diff --git a/x-pack/plugins/lens/public/visualizations/xy/visualization.tsx b/x-pack/plugins/lens/public/visualizations/xy/visualization.tsx index 0d000db6e5206..9f5f9755d1781 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/xy/visualization.tsx @@ -461,6 +461,7 @@ export const getXyVisualization = ({ requiredMinDimensionCount: dataLayer.seriesType.includes('percentage') && hasOnlyOneAccessor ? 1 : 0, enableDimensionEditor: true, + isBreakdownDimension: true, }, ], }; diff --git a/x-pack/test/functional/apps/lens/group4/tsdb.ts b/x-pack/test/functional/apps/lens/group4/tsdb.ts index 7f6045b6f7cf4..3200c7a073dc4 100644 --- a/x-pack/test/functional/apps/lens/group4/tsdb.ts +++ b/x-pack/test/functional/apps/lens/group4/tsdb.ts @@ -248,6 +248,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const elasticChart = getService('elasticChart'); const indexPatterns = getService('indexPatterns'); const esArchiver = getService('esArchiver'); + const comboBox = getService('comboBox'); const createDocs = async ( esIndex: string, @@ -545,6 +546,49 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); } } + + describe('show time series dimension groups within breakdown', () => { + it('should show the time series dimension group on field picker when configuring a breakdown', async () => { + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension', + operation: 'date_histogram', + field: '@timestamp', + }); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', + operation: 'min', + field: 'bytes_counter', + }); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_splitDimensionPanel > lns-empty-dimension', + operation: 'terms', + keepOpen: true, + }); + + const list = await comboBox.getOptionsList('indexPattern-dimension-field'); + expect(list).to.contain('Time series dimensions'); + await PageObjects.lens.closeDimensionEditor(); + }); + + it("should not show the time series dimension group on field picker if it's not a breakdown", async () => { + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', + operation: 'min', + field: 'bytes_counter', + }); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension', + operation: 'date_histogram', + keepOpen: true, + }); + const list = await comboBox.getOptionsList('indexPattern-dimension-field'); + expect(list).to.not.contain('Time series dimensions'); + await PageObjects.lens.closeDimensionEditor(); + }); + }); }); describe('Scenarios with changing stream type', () => { From a371022b8f4e2ffa6fc5f7ed3f92e50a4664d1f9 Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Wed, 9 Aug 2023 18:36:24 +0200 Subject: [PATCH 18/22] [EsAggs] Fix other request merge behaviour when empty string key is retrieved (#163187) ## Summary Fixes #163040 This PR generialize the fix in #150321 to handle also the empty string at parent level when the `Other` response is merged. Added few unit tests to cover some more scenarios. Added some functional tests for top and nested `empty` + `Other` scenarios at higher level (XY + table) The fix affects both Visualize and Lens: Screenshot 2023-08-04 at 18 21 32 Screenshot 2023-08-04 at 18 21 18 Screenshot 2023-08-04 at 18 21 04 Screenshot 2023-08-04 at 18 20 57 Screenshot 2023-08-04 at 18 20 48 Screenshot 2023-08-04 at 18 20 36 Screenshot 2023-08-04 at 18 20 15 Screenshot 2023-08-04 at 18 20 01 Screenshot 2023-08-04 at 18 19 49 Screenshot 2023-08-04 at 18 19 36 Screenshot 2023-08-04 at 18 19 22 Screenshot 2023-08-04 at 18 26 35 ### Checklist Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### Risk Matrix Delete this section if it is not applicable to this PR. Before closing this PR, invite QA, stakeholders, and other developers to identify risks that should be tested prior to the change/feature release. When forming the risk matrix, consider some of the following examples and how they may potentially impact the change: | Risk | Probability | Severity | Mitigation/Notes | |---------------------------|-------------|----------|-------------------------| | Multiple Spaces—unexpected behavior in non-default Kibana Space. | Low | High | Integration tests will verify that all features are still supported in non-default Kibana Space and when user switches between spaces. | | Multiple nodes—Elasticsearch polling might have race conditions when multiple Kibana nodes are polling for the same tasks. | High | Low | Tasks are idempotent, so executing them multiple times will not result in logical error, but will degrade performance. To test for this case we add plenty of unit tests around this logic and document manual testing procedure. | | Code should gracefully handle cases when feature X or plugin Y are disabled. | Medium | High | Unit tests will verify that any feature flag or plugin combination still results in our service operational. | | [See more potential risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) | ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Stratoula Kalafateli --- .../_terms_other_bucket_helper.test.ts | 577 ++++++++++++------ .../buckets/_terms_other_bucket_helper.ts | 48 +- .../definitions/terms/values_input.tsx | 1 + .../test/functional/apps/lens/group3/terms.ts | 155 ++++- .../test/functional/page_objects/lens_page.ts | 14 + 5 files changed, 569 insertions(+), 226 deletions(-) diff --git a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts index e39c858f3e903..981ff3664fbec 100644 --- a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts @@ -10,7 +10,7 @@ import { buildOtherBucketAgg, mergeOtherBucketAggResponse, updateMissingBucket, - OTHER_BUCKET_SEPARATOR as SEP, + OTHER_NESTED_BUCKET_SEPARATOR as SEP, constructSingleTermOtherFilter, } from './_terms_other_bucket_helper'; import type { DataViewField, DataView } from '@kbn/data-views-plugin/common'; @@ -97,188 +97,121 @@ const nestedTerm = { ], }; -const singleTermResponse = { - took: 10, - timed_out: false, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, +function wrapResponse(aggregationResponse: Record) { + return { + took: 3, + timed_out: false, + _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, + hits: { total: 14005, max_score: 0, hits: [] }, + aggregations: aggregationResponse, + status: 200, + }; +} + +const singleTermResponse = wrapResponse({ + '1': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 8325, + buckets: [ + { key: 'ios', doc_count: 2850 }, + { key: 'win xp', doc_count: 2830 }, + { key: '__missing__', doc_count: 1430 }, + ], }, - hits: { - total: 14005, - max_score: 0, - hits: [], - }, - aggregations: { - '1': { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 8325, - buckets: [ - { key: 'ios', doc_count: 2850 }, - { key: 'win xp', doc_count: 2830 }, - { key: '__missing__', doc_count: 1430 }, - ], - }, - }, - status: 200, -}; +}); -const nestedTermResponse = { - took: 10, - timed_out: false, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, - }, - hits: { - total: 14005, - max_score: 0, - hits: [], - }, - aggregations: { - '1': { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 8325, - buckets: [ - { - '2': { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 8325, - buckets: [ - { key: 'ios', doc_count: 2850 }, - { key: 'win xp', doc_count: 2830 }, - { key: '__missing__', doc_count: 1430 }, - ], - }, - key: 'US-with-dash', - doc_count: 2850, +const nestedTermResponse = wrapResponse({ + '1': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 8325, + buckets: [ + { + '2': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 8325, + buckets: [ + { key: 'ios', doc_count: 2850 }, + { key: 'win xp', doc_count: 2830 }, + { key: '__missing__', doc_count: 1430 }, + ], }, - { - '2': { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 8325, - buckets: [ - { key: 'ios', doc_count: 1850 }, - { key: 'win xp', doc_count: 1830 }, - { key: '__missing__', doc_count: 130 }, - ], - }, - key: 'IN-with-dash', - doc_count: 2830, + key: 'US-with-dash', + doc_count: 2850, + }, + { + '2': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 8325, + buckets: [ + { key: 'ios', doc_count: 1850 }, + { key: 'win xp', doc_count: 1830 }, + { key: '__missing__', doc_count: 130 }, + ], }, - ], - }, + key: 'IN-with-dash', + doc_count: 2830, + }, + ], }, - status: 200, -}; +}); -const exhaustiveNestedTermResponse = { - took: 10, - timed_out: false, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, - }, - hits: { - total: 14005, - max_score: 0, - hits: [], - }, - aggregations: { - '1': { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 8325, - buckets: [ - { - '2': { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { key: 'ios', doc_count: 2850 }, - { key: 'win xp', doc_count: 2830 }, - { key: '__missing__', doc_count: 1430 }, - ], - }, - key: 'US-with-dash', - doc_count: 2850, +const exhaustiveNestedTermResponse = wrapResponse({ + '1': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 8325, + buckets: [ + { + '2': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { key: 'ios', doc_count: 2850 }, + { key: 'win xp', doc_count: 2830 }, + { key: '__missing__', doc_count: 1430 }, + ], }, - { - '2': { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { key: 'ios', doc_count: 1850 }, - { key: 'win xp', doc_count: 1830 }, - { key: '__missing__', doc_count: 130 }, - ], - }, - key: 'IN-with-dash', - doc_count: 2830, + key: 'US-with-dash', + doc_count: 2850, + }, + { + '2': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { key: 'ios', doc_count: 1850 }, + { key: 'win xp', doc_count: 1830 }, + { key: '__missing__', doc_count: 130 }, + ], }, - ], - }, + key: 'IN-with-dash', + doc_count: 2830, + }, + ], }, - status: 200, -}; +}); -const nestedTermResponseNoResults = { - took: 10, - timed_out: false, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, - }, - hits: { - total: 0, - max_score: null, - hits: [], - }, - aggregations: { - '1': { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [], - }, +const nestedTermResponseNoResults = wrapResponse({ + '1': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [], }, - status: 200, -}; +}); -const singleOtherResponse = { - took: 3, - timed_out: false, - _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, - hits: { total: 14005, max_score: 0, hits: [] }, - aggregations: { - 'other-filter': { - buckets: { '': { doc_count: 2805 } }, - }, +const singleOtherResponse = wrapResponse({ + 'other-filter': { + buckets: { '': { doc_count: 2805 } }, }, - status: 200, -}; +}); -const nestedOtherResponse = { - took: 3, - timed_out: false, - _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, - hits: { total: 14005, max_score: 0, hits: [] }, - aggregations: { - 'other-filter': { - buckets: { - [`${SEP}US-with-dash`]: { doc_count: 2805 }, - [`${SEP}IN-with-dash`]: { doc_count: 2804 }, - }, +const nestedOtherResponse = wrapResponse({ + 'other-filter': { + buckets: { + [`${SEP}US-with-dash`]: { doc_count: 2805 }, + [`${SEP}IN-with-dash`]: { doc_count: 2804 }, }, }, - status: 200, -}; +}); describe('Terms Agg Other bucket helper', () => { const typesRegistry = mockAggTypesRegistry(); @@ -326,28 +259,12 @@ describe('Terms Agg Other bucket helper', () => { }); test('returns a function for undefined agg buckets', () => { - const response = { - took: 10, - timed_out: false, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, - }, - hits: { - total: 14005, - max_score: 0, - hits: [], - }, - aggregations: { - 2: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 8325, - }, + const response = wrapResponse({ + 2: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 8325, }, - status: 200, - }; + }); const aggConfigs = getAggConfigs(nestedTerm.aggs); const agg = buildOtherBucketAgg( aggConfigs, @@ -706,22 +623,15 @@ describe('Terms Agg Other bucket helper', () => { }, }; - const otherResponse = { - took: 3, - timed_out: false, - _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, - hits: { total: 14005, max_score: 0, hits: [] }, - aggregations: { - 'other-filter': { - buckets: { - [`${SEP}US-with-dash`]: { doc_count: 2805 }, - [`${SEP}IN-with-dash`]: { doc_count: 2804 }, - [`${SEP}`]: { doc_count: 2804 }, - }, + const otherResponse = wrapResponse({ + 'other-filter': { + buckets: { + [`${SEP}US-with-dash`]: { doc_count: 2805 }, + [`${SEP}IN-with-dash`]: { doc_count: 2804 }, + [`${SEP}`]: { doc_count: 2804 }, }, }, - status: 200, - }; + }); const aggConfigs = getAggConfigs(nestedTerm.aggs); const otherAggConfig = buildOtherBucketAgg( aggConfigs, @@ -745,6 +655,269 @@ describe('Terms Agg Other bucket helper', () => { expect((topAgg['1'] as any).buckets[2]['2'].buckets[3].key).toEqual('__other__'); } }); + + test('correctly merges other bucket when the term response contains an empty string', () => { + const response = wrapResponse({ + '0': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 82, + buckets: [ + { + key: '', + doc_count: 657, + }, + { + key: 'ios', + doc_count: 300, + }, + { + key: 'win xp', + doc_count: 284, + }, + { + doc_count: 82, + filters: [ + { + meta: { + type: 'phrases', + key: 'machine.os.raw', + params: ['ios', 'win xp', ''], + negate: true, + }, + query: { + bool: { + should: [ + { + match_phrase: { + 'machine.os.raw': '', + }, + }, + { + match_phrase: { + 'machine.os.raw': 'ios', + }, + }, + { + match_phrase: { + 'machine.os.raw': 'win xp', + }, + }, + ], + minimum_should_match: 1, + }, + }, + }, + ], + key: '__other__', + }, + ], + }, + }); + + const otherResponse = wrapResponse({ + 'other-filter': { + buckets: { + '': { + doc_count: 82, + filters: [ + { + meta: { + type: 'phrases', + key: 'machine.os.raw', + params: ['ios', 'win xp', ''], + negate: true, + }, + query: { + bool: { + should: [ + { + match_phrase: { + 'machine.os.raw': 'ios', + }, + }, + { + match_phrase: { + 'machine.os.raw': 'win xp', + }, + }, + { + match_phrase: { + 'machine.os.raw': '', + }, + }, + ], + minimum_should_match: 1, + }, + }, + }, + ], + key: '__other__', + }, + }, + }, + }); + const aggConfigs = getAggConfigs(singleTerm.aggs); + const otherAggConfig = buildOtherBucketAgg( + aggConfigs, + aggConfigs.aggs[0] as IBucketAggConfig, + enrichResponseWithSampling(response) + ); + + expect(otherAggConfig).toBeDefined(); + if (otherAggConfig) { + const mergedResponse = mergeOtherBucketAggResponse( + aggConfigs, + enrichResponseWithSampling(response), + enrichResponseWithSampling(otherResponse), + aggConfigs.aggs[0] as IBucketAggConfig, + otherAggConfig(), + constructSingleTermOtherFilter + ); + + const topAgg = getTopAggregations(mergedResponse); + const topBuckets = (topAgg['1'] as any).buckets; + expect(topBuckets[2].key).toEqual(''); + expect(topBuckets[2]['2'].buckets[3].key).toEqual('__other__'); + } + }); + + test('correctly merges other bucket with both top and nested terms agg have empty string', () => { + const response = wrapResponse({ + ...nestedTermResponse.aggregations, + '1': { + ...nestedTermResponse.aggregations['1'], + buckets: [ + ...nestedTermResponse.aggregations['1'].buckets, + { + '2': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 8325, + buckets: [ + { key: 'ios', doc_count: 1850 }, + { key: 'win xp', doc_count: 1830 }, + { key: '__missing__', doc_count: 130 }, + { key: '', doc_count: 130 }, + ], + }, + key: '', + doc_count: 2830, + }, + ], + }, + }); + + const otherRootResponse = wrapResponse({ + 'other-filter': { + buckets: { + '': { + '2': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 59, + buckets: [ + { + key: 'US-with-dash', + doc_count: 13, + }, + { + key: 'IN-with-dash', + doc_count: 12, + }, + { + key: '', + doc_count: 12, + }, + ], + }, + doc_count: 84, + key: '__other__', + filters: [ + { + meta: { + type: 'phrases', + key: 'machine.os.raw', + params: ['', 'ios', 'win xp'], + negate: true, + }, + query: { + bool: { + should: [ + { + match_phrase: { + 'machine.os.raw': '', + }, + }, + { + match_phrase: { + 'machine.os.raw': 'ios', + }, + }, + { + match_phrase: { + 'machine.os.raw': 'win xp', + }, + }, + ], + minimum_should_match: 1, + }, + }, + }, + ], + }, + }, + }, + }); + + const otherResponse = wrapResponse({ + 'other-filter': { + buckets: { + [`${SEP}US-with-dash`]: { doc_count: 2805 }, + [`${SEP}IN-with-dash`]: { doc_count: 2804 }, + [`${SEP}`]: { doc_count: 2804 }, + [`${SEP}__other__`]: { doc_count: 3000 }, + }, + }, + }); + const aggConfigs = getAggConfigs(nestedTerm.aggs); + const otherRootAggConfig = buildOtherBucketAgg( + aggConfigs, + aggConfigs.aggs[0] as IBucketAggConfig, + enrichResponseWithSampling(response) + ); + + if (otherRootAggConfig) { + const mergedTopResponse = mergeOtherBucketAggResponse( + aggConfigs, + enrichResponseWithSampling(response), + enrichResponseWithSampling(otherRootResponse), + aggConfigs.aggs[0] as IBucketAggConfig, + otherRootAggConfig(), + constructSingleTermOtherFilter + ); + + const otherAggConfig = buildOtherBucketAgg( + aggConfigs, + aggConfigs.aggs[1] as IBucketAggConfig, + enrichResponseWithSampling(mergedTopResponse) + ); + if (otherAggConfig) { + const mergedResponse = mergeOtherBucketAggResponse( + aggConfigs, + enrichResponseWithSampling(mergedTopResponse), + enrichResponseWithSampling(otherResponse), + aggConfigs.aggs[1] as IBucketAggConfig, + otherAggConfig(), + constructSingleTermOtherFilter + ); + + const topAgg = getTopAggregations(mergedResponse); + expect((topAgg['1'] as any).buckets[2].key).toEqual(''); + expect((topAgg['1'] as any).buckets[2]['2'].buckets[4].key).toEqual('__other__'); + + expect((topAgg['1'] as any).buckets[3].key).toEqual('__other__'); + expect((topAgg['1'] as any).buckets[3]['2'].buckets[3].key).toEqual('__other__'); + } + } + }); }); describe(`updateMissingBucket${getTitlePostfix()}`, () => { diff --git a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts index d4542d1513f16..9737883733266 100644 --- a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts +++ b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts @@ -22,7 +22,9 @@ import { IAggType } from '../agg_type'; import { IAggConfig } from '../agg_config'; import { createSamplerAgg } from '../utils/sampler'; -export const OTHER_BUCKET_SEPARATOR = '╰┄►'; +const MISSING_KEY_STRING = '__missing__'; +export const OTHER_NESTED_BUCKET_SEPARATOR = '╰┄►'; +const otherBucketRegexp = new RegExp(`^${OTHER_NESTED_BUCKET_SEPARATOR}`); /** * walks the aggregation DSL and returns DSL starting at aggregation with id of startFromAggId @@ -56,10 +58,11 @@ const getAggResultBuckets = ( aggWithOtherBucket: IAggConfig, key: string ) => { - const keyParts = key.split(OTHER_BUCKET_SEPARATOR); + const keyParts = key.split(OTHER_NESTED_BUCKET_SEPARATOR); let responseAgg = response; for (const i in keyParts) { - if (keyParts[i] || keyParts[i] === '') { + // enable also the empty string + if (keyParts[i] != null) { const responseAggs: Array> = values(responseAgg); // If you have multi aggs, we cannot just assume the first one is the `other` bucket, // so we need to loop over each agg until we find it. @@ -75,8 +78,13 @@ const getAggResultBuckets = ( return bucketKey === keyParts[i]; }); if (aggResultBucket) { - responseAgg = aggResultBucket; - break; + // this is a special check in order to avoid an overwrite when + // there's an empty string term at root level for the data request + // as the other request will default to empty string category as well + if (!responseAgg?.[aggWithOtherBucket.id] || keyParts[i] !== '') { + responseAgg = aggResultBucket; + break; + } } } } @@ -94,19 +102,20 @@ const getAggResultBuckets = ( * @param aggId: id of the aggregation with missing bucket */ const getAggConfigResultMissingBuckets = (responseAggs: any, aggId: string) => { - const missingKey = '__missing__'; - let resultBuckets: Array> = []; + const resultBuckets: Array> = []; if (responseAggs[aggId]) { const matchingBucket = responseAggs[aggId].buckets.find( - (bucket: Record) => bucket.key === missingKey + (bucket: Record) => bucket.key === MISSING_KEY_STRING ); - if (matchingBucket) resultBuckets.push(matchingBucket); + if (matchingBucket) { + resultBuckets.push(matchingBucket); + } return resultBuckets; } each(responseAggs, (agg) => { if (agg.buckets) { each(agg.buckets, (bucket) => { - resultBuckets = [...resultBuckets, ...getAggConfigResultMissingBuckets(bucket, aggId)]; + resultBuckets.push(...getAggConfigResultMissingBuckets(bucket, aggId)); }); } }); @@ -124,7 +133,7 @@ const getOtherAggTerms = (requestAgg: Record, key: string, otherAgg return requestAgg['other-filter'].filters.filters[key].bool.must_not .filter( (filter: Record) => - filter.match_phrase && filter.match_phrase[otherAgg.params.field.name] + filter.match_phrase && filter.match_phrase[otherAgg.params.field.name] != null // mind empty strings! ) .map((filter: Record) => filter.match_phrase[otherAgg.params.field.name]); }; @@ -220,7 +229,7 @@ export const buildOtherBucketAgg = ( bucket, newAgg.id, newFilters, - `${key}${OTHER_BUCKET_SEPARATOR}${bucketKey.toString()}` + `${key}${OTHER_NESTED_BUCKET_SEPARATOR}${bucketKey.toString()}` ); }); return; @@ -229,7 +238,7 @@ export const buildOtherBucketAgg = ( const hasScriptedField = !!aggWithOtherBucket.params.field?.scripted; const hasMissingBucket = !!aggWithOtherBucket.params.missingBucket; const hasMissingBucketKey = agg.buckets.some( - (bucket: { key: string }) => bucket.key === '__missing__' + (bucket: { key: string }) => bucket.key === MISSING_KEY_STRING ); if ( aggWithOtherBucket.params.field && @@ -246,7 +255,7 @@ export const buildOtherBucketAgg = ( // create not filters for all the buckets each(agg.buckets, (bucket) => { - if (bucket.key === '__missing__') return; + if (bucket.key === MISSING_KEY_STRING) return; const filter = currentAgg.createFilter(currentAgg.getKey(bucket, bucket.key)); filter.meta.negate = true; filters.push(filter); @@ -302,7 +311,7 @@ export const mergeOtherBucketAggResponse = ( 'buckets' in aggregationsRoot!['other-filter'] ? aggregationsRoot!['other-filter'].buckets : {}; each(buckets, (bucket, key) => { if (!bucket.doc_count || key === undefined) return; - const bucketKey = key.replace(new RegExp(`^${OTHER_BUCKET_SEPARATOR}`), ''); + const bucketKey = key.replace(otherBucketRegexp, ''); const aggResultBuckets = getAggResultBuckets( aggsConfig, updatedAggregationsRoot, @@ -319,7 +328,7 @@ export const mergeOtherBucketAggResponse = ( if ( aggResultBuckets.some( - (aggResultBucket: Record) => aggResultBucket.key === '__missing__' + (aggResultBucket: Record) => aggResultBucket.key === MISSING_KEY_STRING ) ) { bucket.filters.push( @@ -330,7 +339,6 @@ export const mergeOtherBucketAggResponse = ( }); return updatedResponse; }; - export const updateMissingBucket = ( response: estypes.SearchResponse, aggConfigs: IAggConfigs, @@ -342,7 +350,7 @@ export const updateMissingBucket = ( agg.id ); aggResultBuckets.forEach((bucket) => { - bucket.key = '__missing__'; + bucket.key = MISSING_KEY_STRING; }); return updatedResponse; }; @@ -394,7 +402,7 @@ export const createOtherBucketPostFlightRequest = ( nestedSearchSource.setField('aggs', filterAgg); - const { rawResponse: response } = await lastValueFrom( + const { rawResponse: otherResponse } = await lastValueFrom( nestedSearchSource.fetch$({ abortSignal, sessionId: searchSessionId, @@ -416,7 +424,7 @@ export const createOtherBucketPostFlightRequest = ( resp = mergeOtherBucketAggResponse( aggConfigs, resp, - response, + otherResponse, aggConfig, filterAgg(), otherFilterBuilder diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/values_input.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/values_input.tsx index 33dd5b7206008..a776227986d68 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/values_input.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/values_input.tsx @@ -94,6 +94,7 @@ export const ValuesInput = ({ const inputNumber = Number(inputValue); setInputValue(String(Math.min(maxValue, Math.max(inputNumber, minValue)))); }} + data-test-subj={'indexPattern-terms-values'} /> ); diff --git a/x-pack/test/functional/apps/lens/group3/terms.ts b/x-pack/test/functional/apps/lens/group3/terms.ts index 3b93c39eb7a6b..f93df80d52589 100644 --- a/x-pack/test/functional/apps/lens/group3/terms.ts +++ b/x-pack/test/functional/apps/lens/group3/terms.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import moment from 'moment'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { @@ -15,6 +16,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const comboBox = getService('comboBox'); const find = getService('find'); const retry = getService('retry'); + const es = getService('es'); + const indexPatterns = getService('indexPatterns'); + const log = getService('log'); describe('lens terms', () => { describe('lens multi terms suite', () => { @@ -127,11 +131,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await retry.try(async () => { // Can not use testSubjects because data-test-subj is placed range input and number input - const percentileInput = await find.byCssSelector( - `input[data-test-subj="lns-indexPattern-percentile-input"][type='number']` + const percentileInput = await PageObjects.lens.getNumericFieldReady( + 'lns-indexPattern-percentile-input' ); - await percentileInput.click(); - await percentileInput.clearValue(); await percentileInput.type('60'); const percentileValue = await percentileInput.getAttribute('value'); @@ -152,5 +154,150 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(data!.bars![0].bars[0].y).to.eql(19265); }); }); + + describe('Enable Other group', () => { + const esIndexPrefix = 'terms-empty-string-index'; + before(async () => { + log.info(`Creating index ${esIndexPrefix} with mappings`); + await es.indices.create({ + index: esIndexPrefix, + mappings: { + properties: { + '@timestamp': { + type: 'date', + }, + a: { + type: 'keyword', + }, + b: { + type: 'keyword', + }, + }, + }, + }); + + log.info(`Adding 100 documents to ${esIndexPrefix} at Sep 20, 2015 @ 06:31:44.000`); + const timestamp = moment + .utc('Sep 20, 2015 @ 06:31:44.000', 'MMM D, YYYY [@] HH:mm:ss.SSS') + .format(); + + await es.bulk({ + index: esIndexPrefix, + body: Array<{ + a: string; + b: string; + '@timestamp': string; + }>(100) + .fill({ a: '', b: '', '@timestamp': timestamp }) + .map((template, i) => { + return { + ...template, + a: i > 50 ? `${(i % 5) + 1}` : '', // generate 5 values for the index + empty string + b: i < 50 ? `${(i % 5) + 1}` : '', // generate 5 values for the index + empty string + }; + }) + .map((d) => `{"index": {}}\n${JSON.stringify(d)}\n`), + }); + + log.info(`Creating dataView ${esIndexPrefix}`); + await indexPatterns.create( + { + title: esIndexPrefix, + timeFieldName: '@timestamp', + }, + { override: true } + ); + }); + + after(async () => { + await es.indices.delete({ + index: esIndexPrefix, + }); + }); + it('should work with empty string values as buckets', async () => { + await PageObjects.visualize.navigateToNewVisualization(); + await PageObjects.visualize.clickVisType('lens'); + await elasticChart.setNewChartUiDebugFlag(true); + await PageObjects.lens.goToTimeRange(); + await PageObjects.lens.switchDataPanelIndexPattern(esIndexPrefix); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', + operation: 'count', + }); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension', + operation: 'terms', + field: 'a', + }); + + await PageObjects.lens.waitForVisualization('xyVisChart'); + const data = await PageObjects.lens.getCurrentChartDebugState('xyVisChart'); + const seriesBar = data!.bars![0].bars; + expect(seriesBar[0].x).to.eql('(empty)'); + expect(seriesBar[seriesBar.length - 1].x).to.eql('Other'); + }); + + it('should work with empty string as breakdown', async () => { + await PageObjects.lens.removeDimension('lnsXY_xDimensionPanel'); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension', + operation: 'date_histogram', + field: '@timestamp', + }); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_splitDimensionPanel > lns-empty-dimension', + operation: 'terms', + field: 'a', + }); + + await PageObjects.lens.waitForVisualization('xyVisChart'); + const data = await PageObjects.lens.getCurrentChartDebugState('xyVisChart'); + expect(data!.bars![0].name).to.eql('(empty)'); + expect(data!.bars![data!.bars!.length - 1].name).to.eql('Other'); + }); + + it('should work with nested empty string values', async () => { + await PageObjects.lens.switchToVisualization('lnsDatatable'); + + await PageObjects.lens.removeLayer(); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsDatatable_rows > lns-empty-dimension', + operation: 'terms', + field: 'a', + keepOpen: true, + }); + await PageObjects.lens.setTermsNumberOfValues(4); + await PageObjects.lens.closeDimensionEditor(); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsDatatable_rows > lns-empty-dimension', + operation: 'terms', + field: 'b', + keepOpen: true, + }); + await PageObjects.lens.setTermsNumberOfValues(1); + await PageObjects.lens.closeDimensionEditor(); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsDatatable_metrics > lns-empty-dimension', + operation: 'count', + }); + await PageObjects.lens.waitForVisualization(); + await PageObjects.common.sleep(20000); + // a empty value + expect(await PageObjects.lens.getDatatableCellText(1, 0)).to.eql('(empty)'); + // b Other value + expect(await PageObjects.lens.getDatatableCellText(1, 1)).to.eql('Other'); + // a Other value + expect(await PageObjects.lens.getDatatableCellText(5, 0)).to.eql('Other'); + // b empty value + expect(await PageObjects.lens.getDatatableCellText(5, 1)).to.eql('(empty)'); + }); + }); }); } diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index 7f95964e0e5d4..a46d90eb915e0 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -689,6 +689,20 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont await this.selectOptionFromComboBox(`indexPattern-dimension-field-${lastIndex}`, field); }); }, + async getNumericFieldReady(testSubj: string) { + const numericInput = await find.byCssSelector( + `input[data-test-subj=${testSubj}][type='number']` + ); + await numericInput.click(); + await numericInput.clearValue(); + return numericInput; + }, + + async setTermsNumberOfValues(value: number) { + const valuesInput = await this.getNumericFieldReady('indexPattern-terms-values'); + await valuesInput.type(`${value}`); + await PageObjects.common.sleep(500); + }, async checkTermsAreNotAvailableToAgg(fields: string[]) { const lastIndex = ( From 949c2fb9db6c35830ccd391339c270e40526c45a Mon Sep 17 00:00:00 2001 From: Carlos Crespo Date: Wed, 9 Aug 2023 18:42:50 +0200 Subject: [PATCH 19/22] [Infra UI] Fix flyout-related tests (#163469) closes [#162672](https://github.com/elastic/kibana/issues/162672) ## Summary This PR fixes the `should render alerts count for a host inside a flyout`. It also moves all flyout-related tests to the `#Single Host Flyout` test. ### How to test ```bash yarn test:ftr:server --config x-pack/test/functional/apps/infra/config.ts ``` ```bash yarn test:ftr:runner --config x-pack/test/functional/apps/infra/config.ts --include x-pack/test/functional/apps/infra/hosts_view.ts ``` https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2830 --- .../test/functional/apps/infra/hosts_view.ts | 383 +++++++++--------- .../page_objects/infra_hosts_view.ts | 12 - 2 files changed, 202 insertions(+), 193 deletions(-) diff --git a/x-pack/test/functional/apps/infra/hosts_view.ts b/x-pack/test/functional/apps/infra/hosts_view.ts index f5dc470587c37..11d0a9675573b 100644 --- a/x-pack/test/functional/apps/infra/hosts_view.ts +++ b/x-pack/test/functional/apps/infra/hosts_view.ts @@ -155,8 +155,15 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { return !!currentUrl.match(path); }); - // Failing: See https://github.com/elastic/kibana/issues/162672 - describe.skip('Hosts View', function () { + const waitForPageToLoad = async () => + await retry.waitFor( + 'wait for table and KPI charts to load', + async () => + (await pageObjects.infraHostsView.isHostTableLoading()) && + (await pageObjects.infraHostsView.isKPIChartsLoaded()) + ); + + describe('Hosts View', function () { before(async () => { await Promise.all([ esArchiver.load('x-pack/test/functional/es_archives/infra/alerts'), @@ -247,189 +254,243 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - describe('#Single host Flyout', () => { + describe('#Single Host Flyout', () => { before(async () => { await setHostViewEnabled(true); await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH); await pageObjects.header.waitUntilLoadingHasFinished(); - await pageObjects.timePicker.setAbsoluteRange( - START_HOST_PROCESSES_DATE.format(timepickerFormat), - END_HOST_PROCESSES_DATE.format(timepickerFormat) - ); - await pageObjects.infraHostsView.clickTableOpenFlyoutButton(); }); - after(async () => { - await retry.try(async () => { - await pageObjects.infraHostsView.clickCloseFlyoutButton(); + describe('Tabs', () => { + before(async () => { + await pageObjects.timePicker.setAbsoluteRange( + START_HOST_PROCESSES_DATE.format(timepickerFormat), + END_HOST_PROCESSES_DATE.format(timepickerFormat) + ); + + await waitForPageToLoad(); + + await pageObjects.infraHostsView.clickTableOpenFlyoutButton(); }); - }); - describe('Overview Tab', () => { - before(async () => { - await pageObjects.infraHostsView.clickOverviewFlyoutTab(); + after(async () => { + await retry.try(async () => { + await pageObjects.infraHostsView.clickCloseFlyoutButton(); + }); }); - [ - { metric: 'cpuUsage', value: '13.9%' }, - { metric: 'normalizedLoad1m', value: '18.8%' }, - { metric: 'memoryUsage', value: '94.9%' }, - { metric: 'diskSpaceUsage', value: 'N/A' }, - ].forEach(({ metric, value }) => { - it(`${metric} tile should show ${value}`, async () => { - await retry.try(async () => { - const tileValue = await pageObjects.infraHostsView.getAssetDetailsKPITileValue( - metric - ); - expect(tileValue).to.eql(value); + describe('Overview Tab', () => { + before(async () => { + await pageObjects.infraHostsView.clickOverviewFlyoutTab(); + }); + + [ + { metric: 'cpuUsage', value: '13.9%' }, + { metric: 'normalizedLoad1m', value: '18.8%' }, + { metric: 'memoryUsage', value: '94.9%' }, + { metric: 'diskSpaceUsage', value: 'N/A' }, + ].forEach(({ metric, value }) => { + it(`${metric} tile should show ${value}`, async () => { + await retry.try(async () => { + const tileValue = await pageObjects.infraHostsView.getAssetDetailsKPITileValue( + metric + ); + expect(tileValue).to.eql(value); + }); }); }); - }); - it('should render 8 charts in the Metrics section', async () => { - const hosts = await pageObjects.infraHostsView.getAssetDetailsMetricsCharts(); - expect(hosts.length).to.equal(8); - }); + it('should render 8 charts in the Metrics section', async () => { + const hosts = await pageObjects.infraHostsView.getAssetDetailsMetricsCharts(); + expect(hosts.length).to.equal(8); + }); - it('should navigate to metadata tab', async () => { - await pageObjects.infraHostsView.clickShowAllMetadataOverviewTab(); - await pageObjects.header.waitUntilLoadingHasFinished(); - await pageObjects.infraHostsView.metadataTableExist(); - await pageObjects.infraHostsView.clickOverviewFlyoutTab(); - }); + it('should navigate to metadata tab', async () => { + await pageObjects.infraHostsView.clickShowAllMetadataOverviewTab(); + await pageObjects.header.waitUntilLoadingHasFinished(); + await pageObjects.infraHostsView.metadataTableExist(); + await pageObjects.infraHostsView.clickOverviewFlyoutTab(); + }); - it('should show alerts', async () => { - await pageObjects.header.waitUntilLoadingHasFinished(); - await pageObjects.infraHostsView.overviewAlertsTitleExist(); - }); + it('should show alerts', async () => { + await pageObjects.header.waitUntilLoadingHasFinished(); + await pageObjects.infraHostsView.overviewAlertsTitleExist(); + }); - it('should open alerts flyout', async () => { - await pageObjects.header.waitUntilLoadingHasFinished(); - await pageObjects.infraHostsView.clickOverviewOpenAlertsFlyout(); - // There are 2 flyouts open (asset details and alerts) - // so we need a stricter selector - // to be sure that we are closing the alerts flyout - const closeAlertFlyout = await find.byCssSelector( - '[aria-labelledby="flyoutRuleAddTitle"] > [data-test-subj="euiFlyoutCloseButton"]' - ); - await closeAlertFlyout.click(); - }); + it('should open alerts flyout', async () => { + await pageObjects.header.waitUntilLoadingHasFinished(); + await pageObjects.infraHostsView.clickOverviewOpenAlertsFlyout(); + // There are 2 flyouts open (asset details and alerts) + // so we need a stricter selector + // to be sure that we are closing the alerts flyout + const closeAlertFlyout = await find.byCssSelector( + '[aria-labelledby="flyoutRuleAddTitle"] > [data-test-subj="euiFlyoutCloseButton"]' + ); + await closeAlertFlyout.click(); + }); - it('should navigate to alerts', async () => { - await pageObjects.infraHostsView.clickOverviewLinkToAlerts(); - await pageObjects.header.waitUntilLoadingHasFinished(); - const url = parse(await browser.getCurrentUrl()); + it('should navigate to alerts', async () => { + await pageObjects.infraHostsView.clickOverviewLinkToAlerts(); + await pageObjects.header.waitUntilLoadingHasFinished(); + const url = parse(await browser.getCurrentUrl()); - const query = decodeURIComponent(url.query ?? ''); + const query = decodeURIComponent(url.query ?? ''); - const alertsQuery = - "_a=(kuery:'host.name:\"Jennys-MBP.fritz.box\"',rangeFrom:'2023-03-28T18:20:00.000Z',rangeTo:'2023-03-28T18:21:00.000Z',status:all)"; + const alertsQuery = + "_a=(kuery:'host.name:\"Jennys-MBP.fritz.box\"',rangeFrom:'2023-03-28T18:20:00.000Z',rangeTo:'2023-03-28T18:21:00.000Z',status:all)"; - expect(url.pathname).to.eql('/app/observability/alerts'); - expect(query).to.contain(alertsQuery); + expect(url.pathname).to.eql('/app/observability/alerts'); + expect(query).to.contain(alertsQuery); - await returnTo(HOSTS_VIEW_PATH); + await returnTo(HOSTS_VIEW_PATH); + }); }); - }); - describe('Metadata Tab', () => { - before(async () => { - await pageObjects.infraHostsView.clickMetadataFlyoutTab(); - }); + describe('Metadata Tab', () => { + before(async () => { + await pageObjects.infraHostsView.clickMetadataFlyoutTab(); + }); - it('should render metadata tab, add and remove filter', async () => { - await pageObjects.infraHostsView.metadataTableExist(); + it('should render metadata tab, add and remove filter', async () => { + await pageObjects.infraHostsView.metadataTableExist(); - // Add Pin - await pageObjects.infraHostsView.clickAddMetadataPin(); - expect(await pageObjects.infraHostsView.getRemovePinExist()).to.be(true); + // Add Pin + await pageObjects.infraHostsView.clickAddMetadataPin(); + expect(await pageObjects.infraHostsView.getRemovePinExist()).to.be(true); - // Persist pin after refresh - await browser.refresh(); - await retry.try(async () => { - await pageObjects.infraHome.waitForLoading(); - const removePinExist = await pageObjects.infraHostsView.getRemovePinExist(); - expect(removePinExist).to.be(true); - }); + // Persist pin after refresh + await browser.refresh(); + await retry.try(async () => { + await pageObjects.infraHome.waitForLoading(); + const removePinExist = await pageObjects.infraHostsView.getRemovePinExist(); + expect(removePinExist).to.be(true); + }); - // Remove Pin - await pageObjects.infraHostsView.clickRemoveMetadataPin(); - expect(await pageObjects.infraHostsView.getRemovePinExist()).to.be(false); + // Remove Pin + await pageObjects.infraHostsView.clickRemoveMetadataPin(); + expect(await pageObjects.infraHostsView.getRemovePinExist()).to.be(false); + + await pageObjects.infraHostsView.clickAddMetadataFilter(); + await pageObjects.header.waitUntilLoadingHasFinished(); + + // Add Filter + const addedFilter = await pageObjects.infraHostsView.getAppliedFilter(); + expect(addedFilter).to.contain('host.architecture: arm64'); + const removeFilterExists = await pageObjects.infraHostsView.getRemoveFilterExist(); + expect(removeFilterExists).to.be(true); + + // Remove filter + await pageObjects.infraHostsView.clickRemoveMetadataFilter(); + await pageObjects.header.waitUntilLoadingHasFinished(); + const removeFilterShouldNotExist = + await pageObjects.infraHostsView.getRemoveFilterExist(); + expect(removeFilterShouldNotExist).to.be(false); + }); - await pageObjects.infraHostsView.clickAddMetadataFilter(); - await pageObjects.header.waitUntilLoadingHasFinished(); + it('should render metadata tab, pin and unpin table row', async () => { + // Add Pin + await pageObjects.infraHostsView.clickAddMetadataPin(); + expect(await pageObjects.infraHostsView.getRemovePinExist()).to.be(true); - // Add Filter - const addedFilter = await pageObjects.infraHostsView.getAppliedFilter(); - expect(addedFilter).to.contain('host.architecture: arm64'); - const removeFilterExists = await pageObjects.infraHostsView.getRemoveFilterExist(); - expect(removeFilterExists).to.be(true); + // Persist pin after refresh + await browser.refresh(); + await retry.try(async () => { + await pageObjects.infraHome.waitForLoading(); + const removePinExist = await pageObjects.infraHostsView.getRemovePinExist(); + expect(removePinExist).to.be(true); + }); - // Remove filter - await pageObjects.infraHostsView.clickRemoveMetadataFilter(); - await pageObjects.header.waitUntilLoadingHasFinished(); - const removeFilterShouldNotExist = - await pageObjects.infraHostsView.getRemoveFilterExist(); - expect(removeFilterShouldNotExist).to.be(false); + // Remove Pin + await pageObjects.infraHostsView.clickRemoveMetadataPin(); + expect(await pageObjects.infraHostsView.getRemovePinExist()).to.be(false); + }); }); - it('should render metadata tab, pin and unpin table row', async () => { - // Add Pin - await pageObjects.infraHostsView.clickAddMetadataPin(); - expect(await pageObjects.infraHostsView.getRemovePinExist()).to.be(true); - - // Persist pin after refresh - await browser.refresh(); - await retry.try(async () => { - await pageObjects.infraHome.waitForLoading(); - const removePinExist = await pageObjects.infraHostsView.getRemovePinExist(); - expect(removePinExist).to.be(true); + describe('Processes Tab', () => { + before(async () => { + await pageObjects.infraHostsView.clickProcessesFlyoutTab(); + }); + it('should render processes tab and with Total Value summary', async () => { + const processesTotalValue = + await pageObjects.infraHostsView.getProcessesTabContentTotalValue(); + const processValue = await processesTotalValue.getVisibleText(); + expect(processValue).to.eql('313'); }); - // Remove Pin - await pageObjects.infraHostsView.clickRemoveMetadataPin(); - expect(await pageObjects.infraHostsView.getRemovePinExist()).to.be(false); + it('should expand processes table row', async () => { + await pageObjects.infraHostsView.getProcessesTable(); + await pageObjects.infraHostsView.getProcessesTableBody(); + await pageObjects.infraHostsView.clickProcessesTableExpandButton(); + }); }); - }); - describe('Processes Tab', () => { - before(async () => { - await pageObjects.infraHostsView.clickProcessesFlyoutTab(); - }); - it('should render processes tab and with Total Value summary', async () => { - const processesTotalValue = - await pageObjects.infraHostsView.getProcessesTabContentTotalValue(); - const processValue = await processesTotalValue.getVisibleText(); - expect(processValue).to.eql('313'); + describe('Logs Tab', () => { + before(async () => { + await pageObjects.infraHostsView.clickLogsFlyoutTab(); + }); + it('should render logs tab', async () => { + await testSubjects.existOrFail('infraAssetDetailsLogsTabContent'); + }); }); - it('should expand processes table row', async () => { - await pageObjects.infraHostsView.getProcessesTable(); - await pageObjects.infraHostsView.getProcessesTableBody(); - await pageObjects.infraHostsView.clickProcessesTableExpandButton(); + describe('Flyout links', () => { + it('should navigate to APM services after click', async () => { + await pageObjects.infraHostsView.clickFlyoutApmServicesLink(); + const url = parse(await browser.getCurrentUrl()); + const query = decodeURIComponent(url.query ?? ''); + const kuery = 'kuery=host.hostname:"Jennys-MBP.fritz.box"'; + + expect(url.pathname).to.eql('/app/apm/services'); + expect(query).to.contain(kuery); + + await returnTo(HOSTS_VIEW_PATH); + }); }); }); - describe('Logs Tab', () => { + describe('Host with alerts', () => { before(async () => { - await pageObjects.infraHostsView.clickLogsFlyoutTab(); + await pageObjects.timePicker.setAbsoluteRange( + START_DATE.format(timepickerFormat), + END_DATE.format(timepickerFormat) + ); + await pageObjects.infraHostsView.clickHostCheckbox('demo-stack-mysql-01', '-'); + await pageObjects.infraHostsView.clickSelectedHostsButton(); + await pageObjects.infraHostsView.clickSelectedHostsAddFilterButton(); + + await waitForPageToLoad(); + + await pageObjects.infraHostsView.clickTableOpenFlyoutButton(); }); - it('should render logs tab', async () => { - await testSubjects.existOrFail('infraAssetDetailsLogsTabContent'); + + after(async () => { + await retry.try(async () => { + await pageObjects.infraHostsView.clickCloseFlyoutButton(); + }); }); - }); - describe('Flyout links', () => { - it('should navigate to APM services after click', async () => { - await pageObjects.infraHostsView.clickFlyoutApmServicesLink(); - const url = parse(await browser.getCurrentUrl()); - const query = decodeURIComponent(url.query ?? ''); - const kuery = 'kuery=host.hostname:"Jennys-MBP.fritz.box"'; + it('should render alerts count for a host inside a flyout', async () => { + await pageObjects.infraHostsView.clickOverviewFlyoutTab(); - expect(url.pathname).to.eql('/app/apm/services'); - expect(query).to.contain(kuery); + retry.tryForTime(30 * 1000, async () => { + await observability.components.alertSummaryWidget.getFullSizeComponentSelectorOrFail(); + }); - await returnTo(HOSTS_VIEW_PATH); + const activeAlertsCount = + await observability.components.alertSummaryWidget.getActiveAlertCount(); + const totalAlertsCount = + await observability.components.alertSummaryWidget.getTotalAlertCount(); + + expect(activeAlertsCount.trim()).to.equal('2'); + expect(totalAlertsCount.trim()).to.equal('3'); + }); + + it('should render "N/A" when processes summary is not available in flyout', async () => { + await pageObjects.infraHostsView.clickProcessesFlyoutTab(); + const processesTotalValue = + await pageObjects.infraHostsView.getProcessesTabContentTotalValue(); + const processValue = await processesTotalValue.getVisibleText(); + expect(processValue).to.eql('N/A'); }); }); }); @@ -444,12 +505,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { END_DATE.format(timepickerFormat) ); - await retry.waitFor( - 'wait for table and KPI charts to load', - async () => - (await pageObjects.infraHostsView.isHostTableLoading()) && - (await pageObjects.infraHostsView.isKPIChartsLoaded()) - ); + await waitForPageToLoad(); }); it('should render the correct page title', async () => { @@ -509,37 +565,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - it('should render alerts count for a host inside a flyout', async () => { - await pageObjects.infraHostsView.clickHostCheckbox('demo-stack-mysql-01', '-'); - await pageObjects.infraHostsView.clickSelectedHostsButton(); - await pageObjects.infraHostsView.clickSelectedHostsAddFilterButton(); - await pageObjects.infraHostsView.clickTableOpenFlyoutButton(); - - const activeAlertsCount = await pageObjects.infraHostsView.getActiveAlertsCountText(); - const totalAlertsCount = await pageObjects.infraHostsView.getTotalAlertsCountText(); - - expect(activeAlertsCount).to.equal('2 '); - expect(totalAlertsCount).to.equal('3'); - - const deleteFilterButton = await find.byCssSelector( - `[title="Delete host.name: demo-stack-mysql-01"]` - ); - await deleteFilterButton.click(); - - await pageObjects.infraHostsView.clickCloseFlyoutButton(); - }); - - it('should render "N/A" when processes summary is not available in flyout', async () => { - await pageObjects.infraHostsView.clickTableOpenFlyoutButton(); - await pageObjects.infraHostsView.clickProcessesFlyoutTab(); - const processesTotalValue = - await pageObjects.infraHostsView.getProcessesTabContentTotalValue(); - const processValue = await processesTotalValue.getVisibleText(); - expect(processValue).to.eql('N/A'); - await pageObjects.infraHostsView.clickCloseFlyoutButton(); - }); - - describe('KPI tiles', () => { + describe('KPIs', () => { [ { metric: 'hostsCount', value: '6' }, { metric: 'cpuUsage', value: '0.8%' }, @@ -673,12 +699,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { before(async () => { await browser.scrollTop(); await pageObjects.infraHostsView.submitQuery(query); - await retry.waitFor( - 'wait for table and KPI charts to load', - async () => - (await pageObjects.infraHostsView.isHostTableLoading()) && - (await pageObjects.infraHostsView.isKPIChartsLoaded()) - ); + await await waitForPageToLoad(); }); after(async () => { diff --git a/x-pack/test/functional/page_objects/infra_hosts_view.ts b/x-pack/test/functional/page_objects/infra_hosts_view.ts index 00ae0af08cf07..6bad2bf1630e5 100644 --- a/x-pack/test/functional/page_objects/infra_hosts_view.ts +++ b/x-pack/test/functional/page_objects/infra_hosts_view.ts @@ -215,18 +215,6 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) { return testSubjects.exists('assetDetailsAlertsTitle'); }, - async getActiveAlertsCountText() { - const container = await testSubjects.find('activeAlertCount'); - const containerText = await container.getVisibleText(); - return containerText; - }, - - async getTotalAlertsCountText() { - const container = await testSubjects.find('totalAlertCount'); - const containerText = await container.getVisibleText(); - return containerText; - }, - async getAssetDetailsMetricsCharts() { const container = await testSubjects.find('assetDetailsMetricsChartGrid'); return container.findAllByCssSelector('[data-test-subj*="infraAssetDetailsMetricsChart"]'); From fb6c9f0898c507029d9196094b7789406a4d8401 Mon Sep 17 00:00:00 2001 From: Achyut Jhunjhunwala Date: Wed, 9 Aug 2023 18:53:12 +0200 Subject: [PATCH 20/22] [APM] FIX trace waterfall loading logic to handle empty scenarios (#163397) ## Summary Closes https://github.com/elastic/kibana/issues/154705 ## List of Issues - Trace Waterfall not clearing and persisting old data ![Trace Explorer Not clearing](https://github.com/elastic/kibana/assets/7416358/5302c5ed-0c92-44ab-81a5-115e32dc8ace) - Infinite Loading of Trace Waterfall where no traces are present and page is reloaded ![Infinite Loading](https://github.com/elastic/kibana/assets/7416358/c5ae1cda-099e-4968-96e5-ad85db38d83a) - After Fixing these 2 issues, found issue with Container Height ![Container Height Issue](https://github.com/elastic/kibana/assets/7416358/7fc7ef1b-68dc-4f52-bc2f-c346cfd5f67e) ## All issues fixed ![All issues resolved](https://github.com/elastic/kibana/assets/7416358/227fe648-d6b9-4788-8961-7369f6ed621a) --- .../transaction_details.cy.ts | 26 +++++++++++++++++++ .../distribution/index.tsx | 6 ++--- .../use_waterfall_fetcher.ts | 5 +++- .../waterfall_with_summary/index.tsx | 5 +++- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/transaction_details.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/transaction_details.cy.ts index dd73051be9f2e..6886fc582f631 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/transaction_details.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/transaction_details.cy.ts @@ -151,4 +151,30 @@ describe('Transaction details', () => { }); }); }); + + describe('when changing filters which results in no trace samples', () => { + it('trace waterfall must reset to empty state', () => { + cy.visitKibana( + `/app/apm/services/opbeans-java/transactions/view?${new URLSearchParams( + { + ...timeRange, + transactionName: 'GET /api/product', + } + )}` + ); + + cy.getByTestSubj('apmWaterfallButton').should('exist'); + + cy.getByTestSubj('apmUnifiedSearchBar') + .type(`_id: "123"`) + .type('{enter}'); + + cy.getByTestSubj('apmWaterfallButton').should('not.exist'); + cy.getByTestSubj('apmNoTraceFound').should('exist'); + + cy.reload(); + + cy.getByTestSubj('apmNoTraceFound').should('exist'); + }); + }); }); diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx index 0c05b945c1b70..47642ebbdc6dc 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx @@ -20,7 +20,7 @@ import { useApmServiceContext } from '../../../../context/apm_service/use_apm_se import { useAnyOfApmParams } from '../../../../hooks/use_apm_params'; import { useTimeRange } from '../../../../hooks/use_time_range'; import { DurationDistributionChartWithScrubber } from '../../../shared/charts/duration_distribution_chart_with_scrubber'; -import { HeightRetainer } from '../../../shared/height_retainer'; +import { ResettingHeightRetainer } from '../../../shared/height_retainer/resetting_height_container'; import { fromQuery, push, toQuery } from '../../../shared/links/url_helpers'; import { TransactionTab } from '../waterfall_with_summary/transaction_tabs'; import { useTransactionDistributionChartData } from './use_transaction_distribution_chart_data'; @@ -99,7 +99,7 @@ export function TransactionDistribution({ ); return ( - +
    -
    + ); } diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/use_waterfall_fetcher.ts b/x-pack/plugins/apm/public/components/app/transaction_details/use_waterfall_fetcher.ts index 81e0d736aee19..a01bb00ea0e44 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/use_waterfall_fetcher.ts +++ b/x-pack/plugins/apm/public/components/app/transaction_details/use_waterfall_fetcher.ts @@ -56,7 +56,10 @@ export function useWaterfallFetcher({ [traceId, start, end, transactionId] ); - const waterfall = useMemo(() => getWaterfall(data), [data]); + const waterfall = useMemo( + () => getWaterfall(traceId ? data : INITIAL_DATA), + [data, traceId] + ); return { waterfall, status, error }; } diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/index.tsx index e19400490133b..a14572f089137 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/index.tsx @@ -60,8 +60,10 @@ export function WaterfallWithSummary({ const isLoading = waterfallFetchResult.status === FETCH_STATUS.LOADING || traceSamplesFetchStatus === FETCH_STATUS.LOADING; + // When traceId is not present, call to waterfallFetchResult will not be initiated const isSucceded = - waterfallFetchResult.status === FETCH_STATUS.SUCCESS && + (waterfallFetchResult.status === FETCH_STATUS.SUCCESS || + waterfallFetchResult.status === FETCH_STATUS.NOT_INITIATED) && traceSamplesFetchStatus === FETCH_STATUS.SUCCESS; useEffect(() => { @@ -96,6 +98,7 @@ export function WaterfallWithSummary({ })} } + data-test-subj="apmNoTraceFound" titleSize="s" /> ); From 9fb83fed865c51e0834fc50c0e4cc19fca2ce649 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Wed, 9 Aug 2023 13:17:07 -0400 Subject: [PATCH 21/22] [Watcher] Re-enable jest tests (#162592) --- .buildkite/disabled_jest_configs.json | 4 +- .../helpers/watch_create_json_page.helpers.ts | 33 ++-- .../watch_create_threshold_page.helpers.ts | 43 ++++-- .../helpers/watch_edit_page.helpers.ts | 11 +- .../helpers/watch_list_page.helpers.ts | 23 ++- .../helpers/watch_status_page.helpers.ts | 24 +-- ...est.ts => watch_create_json_page.test.tsx} | 71 +++++---- .../watch_create_threshold_page.test.tsx | 143 ++++++++++-------- .../watch_edit_page.test.tsx | 20 +-- .../watch_list_page.test.ts | 6 +- .../watch_status_page.test.ts | 14 +- 11 files changed, 233 insertions(+), 159 deletions(-) rename x-pack/plugins/watcher/__jest__/client_integration/{watch_create_json_page.test.ts => watch_create_json_page.test.tsx} (88%) diff --git a/.buildkite/disabled_jest_configs.json b/.buildkite/disabled_jest_configs.json index a64c34ae741b4..fe51488c7066f 100644 --- a/.buildkite/disabled_jest_configs.json +++ b/.buildkite/disabled_jest_configs.json @@ -1,3 +1 @@ -[ - "x-pack/plugins/watcher/jest.config.js" -] +[] diff --git a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_create_json_page.helpers.ts b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_create_json_page.helpers.ts index 6b70f3bdece88..15c9b5b01fe88 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_create_json_page.helpers.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_create_json_page.helpers.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { act } from 'react-dom/test-utils'; + import { registerTestBed, TestBed, AsyncTestBedConfig } from '@kbn/test-jest-helpers'; import { HttpSetup } from '@kbn/core/public'; @@ -24,32 +26,45 @@ const testBedConfig: AsyncTestBedConfig = { export interface WatchCreateJsonTestBed extends TestBed { actions: { - selectTab: (tab: 'edit' | 'simulate') => void; - clickSubmitButton: () => void; - clickSimulateButton: () => void; + selectTab: (tab: 'edit' | 'simulate') => Promise; + clickSubmitButton: () => Promise; + clickSimulateButton: () => Promise; }; } export const setup = async (httpSetup: HttpSetup): Promise => { const initTestBed = registerTestBed(WithAppDependencies(WatchEditPage, httpSetup), testBedConfig); const testBed = await initTestBed(); + const { find, component } = testBed; /** * User Actions */ - const selectTab = (tab: 'edit' | 'simulate') => { + const selectTab = async (tab: 'edit' | 'simulate') => { const tabs = ['edit', 'simulate']; - testBed.find('tab').at(tabs.indexOf(tab)).simulate('click'); + await act(async () => { + find('tab').at(tabs.indexOf(tab)).simulate('click'); + }); + + component.update(); }; - const clickSubmitButton = () => { - testBed.find('saveWatchButton').simulate('click'); + const clickSubmitButton = async () => { + await act(async () => { + testBed.find('saveWatchButton').simulate('click'); + }); + + component.update(); }; - const clickSimulateButton = () => { - testBed.find('simulateWatchButton').simulate('click'); + const clickSimulateButton = async () => { + await act(async () => { + testBed.find('simulateWatchButton').simulate('click'); + }); + + component.update(); }; return { diff --git a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_create_threshold_page.helpers.ts b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_create_threshold_page.helpers.ts index d2bb49a861167..b64ea8b003843 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_create_threshold_page.helpers.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_create_threshold_page.helpers.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { act } from 'react-dom/test-utils'; + import { registerTestBed, TestBed, AsyncTestBedConfig } from '@kbn/test-jest-helpers'; import { HttpSetup } from '@kbn/core/public'; @@ -24,39 +26,56 @@ const testBedConfig: AsyncTestBedConfig = { export interface WatchCreateThresholdTestBed extends TestBed { actions: { - clickSubmitButton: () => void; - clickAddActionButton: () => void; + clickSubmitButton: () => Promise; + clickAddActionButton: () => Promise; clickActionLink: ( actionType: 'logging' | 'email' | 'webhook' | 'index' | 'slack' | 'jira' | 'pagerduty' - ) => void; - clickSimulateButton: () => void; + ) => Promise; + clickSimulateButton: () => Promise; }; } export const setup = async (httpSetup: HttpSetup): Promise => { const initTestBed = registerTestBed(WithAppDependencies(WatchEditPage, httpSetup), testBedConfig); const testBed = await initTestBed(); + const { find, component } = testBed; /** * User Actions */ - const clickSubmitButton = () => { - testBed.find('saveWatchButton').simulate('click'); + const clickSubmitButton = async () => { + await act(async () => { + find('saveWatchButton').simulate('click'); + }); + + component.update(); }; - const clickAddActionButton = () => { - testBed.find('addWatchActionButton').simulate('click'); + const clickAddActionButton = async () => { + await act(async () => { + find('addWatchActionButton').simulate('click'); + }); + + component.update(); }; - const clickSimulateButton = () => { - testBed.find('simulateActionButton').simulate('click'); + const clickSimulateButton = async () => { + await act(async () => { + find('simulateActionButton').simulate('click'); + }); + + component.update(); }; - const clickActionLink = ( + const clickActionLink = async ( actionType: 'logging' | 'email' | 'webhook' | 'index' | 'slack' | 'jira' | 'pagerduty' ) => { - testBed.find(`${actionType}ActionButton`).simulate('click'); + await act(async () => { + find(`${actionType}ActionButton`).simulate('click'); + }); + + component.update(); }; return { diff --git a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_edit_page.helpers.ts b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_edit_page.helpers.ts index 20f8389c0fec7..8e528af2b3366 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_edit_page.helpers.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_edit_page.helpers.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { act } from 'react-dom/test-utils'; import { registerTestBed, TestBed, AsyncTestBedConfig } from '@kbn/test-jest-helpers'; import { HttpSetup } from '@kbn/core/public'; @@ -25,7 +26,7 @@ const testBedConfig: AsyncTestBedConfig = { export interface WatchEditTestBed extends TestBed { actions: { - clickSubmitButton: () => void; + clickSubmitButton: () => Promise; }; } @@ -37,8 +38,12 @@ export const setup = async (httpSetup: HttpSetup): Promise => * User Actions */ - const clickSubmitButton = () => { - testBed.find('saveWatchButton').simulate('click'); + const clickSubmitButton = async () => { + await act(async () => { + testBed.find('saveWatchButton').simulate('click'); + }); + + testBed.component.update(); }; return { diff --git a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_list_page.helpers.ts b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_list_page.helpers.ts index 3361619ee9dbb..cd4fd2ab2cfba 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_list_page.helpers.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_list_page.helpers.ts @@ -27,9 +27,9 @@ const testBedConfig: AsyncTestBedConfig = { export interface WatchListTestBed extends TestBed { actions: { - selectWatchAt: (index: number) => void; - clickWatchActionAt: (index: number, action: 'delete' | 'edit') => void; - searchWatches: (term: string) => void; + selectWatchAt: (index: number) => Promise; + clickWatchActionAt: (index: number, action: 'delete' | 'edit') => Promise; + searchWatches: (term: string) => Promise; advanceTimeToTableRefresh: () => Promise; }; } @@ -42,11 +42,15 @@ export const setup = async (httpSetup: HttpSetup): Promise => * User Actions */ - const selectWatchAt = (index: number) => { + const selectWatchAt = async (index: number) => { const { rows } = testBed.table.getMetaData('watchesTable'); const row = rows[index]; const checkBox = row.reactWrapper.find('input').hostNodes(); - checkBox.simulate('change', { target: { checked: true } }); + + await act(async () => { + checkBox.simulate('change', { target: { checked: true } }); + }); + testBed.component.update(); }; const clickWatchActionAt = async (index: number, action: 'delete' | 'edit') => { @@ -58,18 +62,21 @@ export const setup = async (httpSetup: HttpSetup): Promise => await act(async () => { button.simulate('click'); - component.update(); }); + component.update(); }; - const searchWatches = (term: string) => { + const searchWatches = async (term: string) => { const { find, component } = testBed; const searchInput = find('watchesTableContainer').find('.euiFieldSearch'); // Enter input into the search box // @ts-ignore searchInput.instance().value = term; - searchInput.simulate('keyup', { key: 'Enter', keyCode: 13, which: 13 }); + + await act(async () => { + searchInput.simulate('keyup', { key: 'Enter', keyCode: 13, which: 13 }); + }); component.update(); }; diff --git a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_status_page.helpers.ts b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_status_page.helpers.ts index 601857ca941f0..7c6da257b1700 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_status_page.helpers.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_status_page.helpers.ts @@ -32,11 +32,11 @@ const testBedConfig: AsyncTestBedConfig = { export interface WatchStatusTestBed extends TestBed { actions: { - selectTab: (tab: 'execution history' | 'action statuses') => void; - clickToggleActivationButton: () => void; - clickAcknowledgeButton: (index: number) => void; - clickDeleteWatchButton: () => void; - clickWatchExecutionAt: (index: number, tableCellText: string) => void; + selectTab: (tab: 'execution history' | 'action statuses') => Promise; + clickToggleActivationButton: () => Promise; + clickAcknowledgeButton: (index: number) => Promise; + clickDeleteWatchButton: () => Promise; + clickWatchExecutionAt: (index: number, tableCellText: string) => Promise; }; } @@ -51,10 +51,14 @@ export const setup = async (httpSetup: HttpSetup): Promise = * User Actions */ - const selectTab = (tab: 'execution history' | 'action statuses') => { + const selectTab = async (tab: 'execution history' | 'action statuses') => { + const { component, find } = testBed; const tabs = ['execution history', 'action statuses']; - testBed.find('tab').at(tabs.indexOf(tab)).simulate('click'); + await act(async () => { + find('tab').at(tabs.indexOf(tab)).simulate('click'); + }); + component.update(); }; const clickToggleActivationButton = async () => { @@ -63,8 +67,8 @@ export const setup = async (httpSetup: HttpSetup): Promise = await act(async () => { button.simulate('click'); - component.update(); }); + component.update(); }; const clickAcknowledgeButton = async (index: number) => { @@ -76,8 +80,8 @@ export const setup = async (httpSetup: HttpSetup): Promise = await act(async () => { button.simulate('click'); - component.update(); }); + component.update(); }; const clickDeleteWatchButton = async () => { @@ -86,8 +90,8 @@ export const setup = async (httpSetup: HttpSetup): Promise = await act(async () => { button.simulate('click'); - component.update(); }); + component.update(); }; const clickWatchExecutionAt = async (index: number, tableCellText: string) => { diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json_page.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json_page.test.tsx similarity index 88% rename from x-pack/plugins/watcher/__jest__/client_integration/watch_create_json_page.test.ts rename to x-pack/plugins/watcher/__jest__/client_integration/watch_create_json_page.test.tsx index f79a72b456afb..f6231ab328d25 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json_page.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_json_page.test.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import React from 'react'; import { act } from 'react-dom/test-utils'; import { getExecuteDetails } from '../../__fixtures__'; @@ -16,12 +17,29 @@ import { WATCH } from './helpers/jest_constants'; const { setup } = pageHelpers.watchCreateJsonPage; +jest.mock('@kbn/kibana-react-plugin/public', () => { + const original = jest.requireActual('@kbn/kibana-react-plugin/public'); + return { + ...original, + // Mocking CodeEditor, which uses React Monaco under the hood + CodeEditor: (props: any) => ( + { + props.onChange(e.jsonContent); + }} + /> + ), + }; +}); + describe(' create route', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); let testBed: WatchCreateJsonTestBed; beforeAll(() => { - jest.useFakeTimers({ legacyFakeTimers: true }); + jest.useFakeTimers(); }); afterAll(() => { @@ -30,7 +48,10 @@ describe(' create route', () => { describe('on component mount', () => { beforeEach(async () => { - testBed = await setup(httpSetup); + await act(async () => { + testBed = await setup(httpSetup); + }); + testBed.component.update(); }); @@ -47,13 +68,13 @@ describe(' create route', () => { expect(find('tab').map((t) => t.text())).toEqual(['Edit', 'Simulate']); }); - test('should navigate to the "Simulate" tab', () => { + test('should navigate to the "Simulate" tab', async () => { const { exists, actions } = testBed; expect(exists('jsonWatchForm')).toBe(true); expect(exists('jsonWatchSimulateForm')).toBe(false); - actions.selectTab('simulate'); + await actions.selectTab('simulate'); expect(exists('jsonWatchForm')).toBe(false); expect(exists('jsonWatchSimulateForm')).toBe(true); @@ -62,19 +83,19 @@ describe(' create route', () => { describe('create', () => { describe('form validation', () => { - test('should not allow empty ID field', () => { + test('should not allow empty ID field', async () => { const { form, actions } = testBed; form.setInputValue('idInput', ''); - actions.clickSubmitButton(); + await actions.clickSubmitButton(); expect(form.getErrorsMessages()).toContain('ID is required'); }); - test('should not allow invalid characters for ID field', () => { + test('should not allow invalid characters for ID field', async () => { const { form, actions } = testBed; form.setInputValue('idInput', 'invalid$id*field/'); - actions.clickSubmitButton(); + await actions.clickSubmitButton(); expect(form.getErrorsMessages()).toContain( 'ID can only contain letters, underscores, dashes, periods and numbers.' @@ -90,9 +111,7 @@ describe(' create route', () => { form.setInputValue('nameInput', watch.name); form.setInputValue('idInput', watch.id); - await act(async () => { - actions.clickSubmitButton(); - }); + await actions.clickSubmitButton(); const DEFAULT_LOGGING_ACTION_ID = 'logging_1'; const DEFAULT_LOGGING_ACTION_TYPE = 'logging'; @@ -125,7 +144,7 @@ describe(' create route', () => { }); test('should surface the API errors from the "save" HTTP request', async () => { - const { form, actions, component, exists, find } = testBed; + const { form, actions, exists, find } = testBed; const { watch } = WATCH; form.setInputValue('nameInput', watch.name); @@ -140,10 +159,7 @@ describe(' create route', () => { httpRequestsMockHelpers.setSaveWatchResponse(watch.id, undefined, error); - await act(async () => { - actions.clickSubmitButton(); - }); - component.update(); + await actions.clickSubmitButton(); expect(exists('sectionError')).toBe(true); expect(find('sectionError').text()).toContain(error.message); @@ -152,12 +168,13 @@ describe(' create route', () => { }); describe('simulate', () => { - beforeEach(() => { + beforeEach(async () => { const { actions, form } = testBed; // Set watch id (required field) and switch to simulate tab form.setInputValue('idInput', WATCH.watch.id); - actions.selectTab('simulate'); + + await actions.selectTab('simulate'); }); describe('form payload & API errors', () => { @@ -167,9 +184,7 @@ describe(' create route', () => { watch: { id, type }, } = WATCH; - await act(async () => { - actions.clickSimulateButton(); - }); + await actions.clickSimulateButton(); const actionModes = Object.keys(defaultWatch.actions).reduce( (actionAccum: any, action) => { @@ -202,7 +217,7 @@ describe(' create route', () => { }); test('should execute a watch with a valid payload', async () => { - const { actions, form, find, exists, component } = testBed; + const { actions, form, find, exists } = testBed; const { watch: { id, type }, } = WATCH; @@ -228,10 +243,7 @@ describe(' create route', () => { }, }); - await act(async () => { - actions.clickSimulateButton(); - }); - component.update(); + await actions.clickSimulateButton(); const actionModes = Object.keys(defaultWatch.actions).reduce( (actionAccum: any, action) => { @@ -303,7 +315,7 @@ describe(' create route', () => { conditionMet ? 'when the condition is met' : 'when the condition is not met', () => { beforeEach(async () => { - const { actions, component, form } = testBed; + const { actions, form } = testBed; form.setInputValue('actionModesSelect', actionMode); httpRequestsMockHelpers.setLoadExecutionResultResponse({ @@ -335,10 +347,7 @@ describe(' create route', () => { }, }); - await act(async () => { - actions.clickSimulateButton(); - }); - component.update(); + await actions.clickSimulateButton(); }); test('should set the correct condition met status', () => { diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold_page.test.tsx b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold_page.test.tsx index d7df7efd7be12..8260bd75ebb04 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold_page.test.tsx +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_create_threshold_page.test.tsx @@ -23,16 +23,6 @@ const MATCH_INDICES = ['index1']; const ES_FIELDS = [{ name: '@timestamp', type: 'date' }]; -// Since watchID's are dynamically created, we have to mock -// the function that generates them in order to be able to match -// against it. -jest.mock('uuid', () => ({ - v4: () => { - // eslint-disable-next-line @typescript-eslint/no-var-requires - return require('./helpers/jest_constants').WATCH_ID; - }, -})); - const SETTINGS = { action_types: { email: { enabled: true }, @@ -55,6 +45,37 @@ const WATCH_VISUALIZE_DATA = { }, }; +// Since watchID's are dynamically created, we have to mock +// the function that generates them in order to be able to match +// against it. +jest.mock('uuid', () => ({ + v4: () => { + // eslint-disable-next-line @typescript-eslint/no-var-requires + return require('./helpers/jest_constants').WATCH_ID; + }, + v1: () => { + // eslint-disable-next-line @typescript-eslint/no-var-requires + return require('./helpers/jest_constants').WATCH_ID; + }, +})); + +jest.mock('@kbn/kibana-react-plugin/public', () => { + const original = jest.requireActual('@kbn/kibana-react-plugin/public'); + return { + ...original, + // Mocking CodeEditor, which uses React Monaco under the hood + CodeEditor: (props: any) => ( + { + props.onChange(e.jsonContent); + }} + /> + ), + }; +}); + jest.mock('@elastic/eui', () => { const original = jest.requireActual('@elastic/eui'); @@ -82,22 +103,27 @@ describe(' create route', () => { let testBed: WatchCreateThresholdTestBed; beforeAll(() => { - jest.useFakeTimers({ legacyFakeTimers: true }); + jest.useFakeTimers(); }); afterAll(() => { jest.useRealTimers(); }); - describe('on component mount', () => { - beforeEach(async () => { - await act(async () => { - testBed = await setup(httpSetup); - }); + httpRequestsMockHelpers.setLoadMatchingIndicesResponse({ indices: MATCH_INDICES }); + httpRequestsMockHelpers.setLoadEsFieldsResponse({ fields: ES_FIELDS }); + httpRequestsMockHelpers.setLoadSettingsResponse(SETTINGS); + httpRequestsMockHelpers.setLoadWatchVisualizeResponse(WATCH_VISUALIZE_DATA); - testBed.component.update(); + beforeEach(async () => { + await act(async () => { + testBed = await setup(httpSetup); }); + testBed.component.update(); + }); + + describe('on component mount', () => { test('should set the correct page title', () => { const { find } = testBed; @@ -105,13 +131,6 @@ describe(' create route', () => { }); describe('create', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadMatchingIndicesResponse({ indices: MATCH_INDICES }); - httpRequestsMockHelpers.setLoadEsFieldsResponse({ fields: ES_FIELDS }); - httpRequestsMockHelpers.setLoadSettingsResponse(SETTINGS); - httpRequestsMockHelpers.setLoadWatchVisualizeResponse(WATCH_VISUALIZE_DATA); - }); - describe('form validation', () => { test('should not allow empty name field', () => { const { form } = testBed; @@ -216,14 +235,21 @@ describe(' create route', () => { describe('actions', () => { beforeEach(async () => { + await act(async () => { + testBed = await setup(httpSetup); + }); + const { form, find, component } = testBed; + component.update(); + // Set up valid fields needed for actions component to render await act(async () => { form.setInputValue('nameInput', WATCH_NAME); find('indicesComboBox').simulate('change', [{ label: 'index1', value: 'index1' }]); form.setInputValue('watchTimeFieldSelect', WATCH_TIME_FIELD); }); + component.update(); }); @@ -232,8 +258,8 @@ describe(' create route', () => { const LOGGING_MESSAGE = 'test log message'; - actions.clickAddActionButton(); - actions.clickActionLink('logging'); + await actions.clickAddActionButton(); + await actions.clickActionLink('logging'); expect(exists('watchActionAccordion')).toBe(true); @@ -246,9 +272,7 @@ describe(' create route', () => { // Next, provide valid field and verify form.setInputValue('loggingTextInput', LOGGING_MESSAGE); - await act(async () => { - actions.clickSimulateButton(); - }); + await actions.clickSimulateButton(); const thresholdWatch = { id: WATCH_ID, @@ -300,17 +324,15 @@ describe(' create route', () => { test('should simulate an index action', async () => { const { form, actions, exists } = testBed; - actions.clickAddActionButton(); - actions.clickActionLink('index'); + await actions.clickAddActionButton(); + await actions.clickActionLink('index'); expect(exists('watchActionAccordion')).toBe(true); // Verify an empty index is allowed form.setInputValue('indexInput', ''); - await act(async () => { - actions.clickSimulateButton(); - }); + await actions.clickSimulateButton(); const thresholdWatch = { id: WATCH_ID, @@ -363,16 +385,14 @@ describe(' create route', () => { const SLACK_MESSAGE = 'test slack message'; - actions.clickAddActionButton(); - actions.clickActionLink('slack'); + await actions.clickAddActionButton(); + await actions.clickActionLink('slack'); expect(exists('watchActionAccordion')).toBe(true); form.setInputValue('slackMessageTextarea', SLACK_MESSAGE); - await act(async () => { - actions.clickSimulateButton(); - }); + await actions.clickSimulateButton(); const thresholdWatch = { id: WATCH_ID, @@ -430,8 +450,8 @@ describe(' create route', () => { const EMAIL_SUBJECT = 'test email subject'; const EMAIL_BODY = 'this is a test email body'; - actions.clickAddActionButton(); - actions.clickActionLink('email'); + await actions.clickAddActionButton(); + await actions.clickActionLink('email'); expect(exists('watchActionAccordion')).toBe(true); @@ -442,9 +462,7 @@ describe(' create route', () => { form.setInputValue('emailSubjectInput', EMAIL_SUBJECT); form.setInputValue('emailBodyInput', EMAIL_BODY); - await act(async () => { - actions.clickSimulateButton(); - }); + await actions.clickSimulateButton(); const thresholdWatch = { id: WATCH_ID, @@ -510,8 +528,8 @@ describe(' create route', () => { const USERNAME = 'test_user'; const PASSWORD = 'test_password'; - actions.clickAddActionButton(); - actions.clickActionLink('webhook'); + await actions.clickAddActionButton(); + await actions.clickActionLink('webhook'); expect(exists('watchActionAccordion')).toBe(true); @@ -534,9 +552,7 @@ describe(' create route', () => { form.setInputValue('webhookUsernameInput', USERNAME); form.setInputValue('webhookPasswordInput', PASSWORD); - await act(async () => { - actions.clickSimulateButton(); - }); + await actions.clickSimulateButton(); const thresholdWatch = { id: WATCH_ID, @@ -600,14 +616,18 @@ describe(' create route', () => { const ISSUE_TYPE = 'Bug'; const SUMMARY = 'test Jira summary'; - actions.clickAddActionButton(); - actions.clickActionLink('jira'); + await actions.clickAddActionButton(); + await actions.clickActionLink('jira'); expect(exists('watchActionAccordion')).toBe(true); - // First, provide invalid fields and verify - form.setInputValue('jiraProjectKeyInput', ''); + // Set issue type value and clear it to trigger required error message + form.setInputValue('jiraIssueTypeInput', 'myissue'); form.setInputValue('jiraIssueTypeInput', ''); + // Set project type value and clear it to trigger required error message + form.setInputValue('jiraProjectKeyInput', 'my key'); + form.setInputValue('jiraProjectKeyInput', ''); + // Clear default summary to trigger required error message form.setInputValue('jiraSummaryInput', ''); expect(form.getErrorsMessages()).toEqual([ @@ -622,9 +642,7 @@ describe(' create route', () => { form.setInputValue('jiraIssueTypeInput', ISSUE_TYPE); form.setInputValue('jiraSummaryInput', SUMMARY); - await act(async () => { - actions.clickSimulateButton(); - }); + await actions.clickSimulateButton(); const thresholdWatch = { id: WATCH_ID, @@ -688,8 +706,8 @@ describe(' create route', () => { const DESCRIPTION = 'test pagerduty description'; - actions.clickAddActionButton(); - actions.clickActionLink('pagerduty'); + await actions.clickAddActionButton(); + await actions.clickActionLink('pagerduty'); expect(exists('watchActionAccordion')).toBe(true); @@ -702,9 +720,7 @@ describe(' create route', () => { // Next, provide valid fields and verify form.setInputValue('pagerdutyDescriptionInput', DESCRIPTION); - await act(async () => { - actions.clickSimulateButton(); - }); + await actions.clickSimulateButton(); const thresholdWatch = { id: WATCH_ID, @@ -757,7 +773,6 @@ describe(' create route', () => { describe('watch visualize data payload', () => { test('should send the correct payload', async () => { const { form, find, component } = testBed; - // Set up required fields await act(async () => { form.setInputValue('nameInput', WATCH_NAME); @@ -807,9 +822,7 @@ describe(' create route', () => { }); component.update(); - await act(async () => { - actions.clickSubmitButton(); - }); + await actions.clickSubmitButton(); expect(httpSetup.put).toHaveBeenLastCalledWith( `${API_BASE_PATH}/watch/${WATCH_ID}`, diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_edit_page.test.tsx b/x-pack/plugins/watcher/__jest__/client_integration/watch_edit_page.test.tsx index ba38fbd5b3cc7..b00f9916970b9 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_edit_page.test.tsx +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_edit_page.test.tsx @@ -39,7 +39,7 @@ describe('', () => { let testBed: WatchEditTestBed; beforeAll(() => { - jest.useFakeTimers({ legacyFakeTimers: true }); + jest.useFakeTimers(); }); afterAll(() => { @@ -50,7 +50,10 @@ describe('', () => { beforeEach(async () => { httpRequestsMockHelpers.setLoadWatchResponse(WATCH_ID, WATCH); - testBed = await setup(httpSetup); + await act(async () => { + testBed = await setup(httpSetup); + }); + testBed.component.update(); }); @@ -82,9 +85,7 @@ describe('', () => { form.setInputValue('nameInput', EDITED_WATCH_NAME); - await act(async () => { - actions.clickSubmitButton(); - }); + await actions.clickSubmitButton(); const DEFAULT_LOGGING_ACTION_ID = 'logging_1'; const DEFAULT_LOGGING_ACTION_TYPE = 'logging'; @@ -137,7 +138,10 @@ describe('', () => { beforeEach(async () => { httpRequestsMockHelpers.setLoadWatchResponse(WATCH_ID, { watch }); - testBed = await setup(httpSetup); + await act(async () => { + testBed = await setup(httpSetup); + }); + testBed.component.update(); }); @@ -162,9 +166,7 @@ describe('', () => { form.setInputValue('nameInput', EDITED_WATCH_NAME); - await act(async () => { - actions.clickSubmitButton(); - }); + await actions.clickSubmitButton(); const { id, diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_list_page.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_list_page.test.ts index c9116f45c9314..8eacd4841c666 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_list_page.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_list_page.test.ts @@ -18,7 +18,7 @@ describe('', () => { let testBed: WatchListTestBed; beforeAll(() => { - jest.useFakeTimers({ legacyFakeTimers: true }); + jest.useFakeTimers(); }); afterAll(() => { @@ -79,7 +79,7 @@ describe('', () => { test('should show error callout if search is invalid', async () => { const { exists, actions } = testBed; - actions.searchWatches('or'); + await actions.searchWatches('or'); expect(exists('watcherListSearchError')).toBe(true); }); @@ -87,7 +87,7 @@ describe('', () => { test('should retain the search query', async () => { const { table, actions } = testBed; - actions.searchWatches(watch1.name); + await actions.searchWatches(watch1.name); const { tableCellsValues } = table.getMetaData('watchesTable'); diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_status_page.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_status_page.test.ts index 20b503d82ad1d..d40015776065f 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_status_page.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_status_page.test.ts @@ -45,7 +45,7 @@ describe('', () => { let testBed: WatchStatusTestBed; beforeAll(() => { - jest.useFakeTimers({ legacyFakeTimers: true }); + jest.useFakeTimers(); }); afterAll(() => { @@ -57,7 +57,9 @@ describe('', () => { httpRequestsMockHelpers.setLoadWatchResponse(WATCH_ID, { watch }); httpRequestsMockHelpers.setLoadWatchHistoryResponse(WATCH_ID, watchHistoryItems); - testBed = await setup(httpSetup); + await act(async () => { + testBed = await setup(httpSetup); + }); testBed.component.update(); }); @@ -75,13 +77,13 @@ describe('', () => { expect(find('tab').map((t) => t.text())).toEqual(['Execution history', 'Action statuses']); }); - test('should navigate to the "Action statuses" tab', () => { + test('should navigate to the "Action statuses" tab', async () => { const { exists, actions } = testBed; expect(exists('watchHistorySection')).toBe(true); expect(exists('watchDetailSection')).toBe(false); - actions.selectTab('action statuses'); + await actions.selectTab('action statuses'); expect(exists('watchHistorySection')).toBe(false); expect(exists('watchDetailSection')).toBe(true); @@ -222,10 +224,10 @@ describe('', () => { }); describe('action statuses', () => { - beforeEach(() => { + beforeEach(async () => { const { actions } = testBed; - actions.selectTab('action statuses'); + await actions.selectTab('action statuses'); }); test('should list the watch actions in a table', () => { From 6673e9dc59f8199b5eea8531a924b51a09622b58 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 9 Aug 2023 18:32:46 +0100 Subject: [PATCH 22/22] [ML] Fixing capabilites polling in manage page (#163399) On ML's management page a new capabilities poll is created every time the user changes tabs. `getMlGlobalServices` gets called every time the jobs list renders, which creates a new `MlCapabilitiesService` which creates a new timer to poll for ml's capabilities. This change moves the `mlServices` so it isn't called on each render. It also bumps up the interval from 1 min to 5 mins as think 1 min is a bit too frequent. --- .../public/application/capabilities/check_capabilities.ts | 2 +- .../jobs_list/components/jobs_list_page/jobs_list_page.tsx | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts b/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts index 72a6100c15a7c..c5325f4aa7614 100644 --- a/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts +++ b/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts @@ -24,7 +24,7 @@ import { type MlApiServices } from '../services/ml_api_service'; let _capabilities: MlCapabilities = getDefaultCapabilities(); -const CAPABILITIES_REFRESH_INTERVAL = 60000; +const CAPABILITIES_REFRESH_INTERVAL = 5 * 60 * 1000; // 5min; export class MlCapabilitiesService { private _isLoading$ = new BehaviorSubject(true); diff --git a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx index e4b79eafb896d..6941e53cd68b2 100644 --- a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx +++ b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx @@ -70,6 +70,11 @@ export const JobsListPage: FC<{ const I18nContext = coreStart.i18n.Context; const theme$ = coreStart.theme.theme$; + const mlServices = useMemo( + () => getMlGlobalServices(coreStart.http, usageCollection), + [coreStart.http, usageCollection] + ); + const check = async () => { try { await checkGetManagementMlJobsResolver(mlApiServices); @@ -122,7 +127,7 @@ export const JobsListPage: FC<{ usageCollection, fieldFormats, spacesApi, - mlServices: getMlGlobalServices(coreStart.http, usageCollection), + mlServices, }} >