From 2645865000e56d7359c4ca555075f5888fad0020 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 13 Feb 2024 15:54:52 +0000 Subject: [PATCH 01/15] skip flaky suite (#172599) --- .../security_roles_privileges.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/reporting_functional/reporting_and_deprecated_security/security_roles_privileges.ts b/x-pack/test/reporting_functional/reporting_and_deprecated_security/security_roles_privileges.ts index f9b84469c1eee..67e0012df4e26 100644 --- a/x-pack/test/reporting_functional/reporting_and_deprecated_security/security_roles_privileges.ts +++ b/x-pack/test/reporting_functional/reporting_and_deprecated_security/security_roles_privileges.ts @@ -24,7 +24,8 @@ export default function ({ getService }: FtrProviderContext) { await reportingFunctional.teardownEcommerce(); }); - describe('Dashboard: Download CSV file', () => { + // FLAKY: https://github.com/elastic/kibana/issues/172599 + describe.skip('Dashboard: Download CSV file', () => { it('does not allow user that does not have reporting_user role', async () => { await reportingFunctional.loginDataAnalyst(); await reportingFunctional.openSavedDashboard(DASHBOARD_TITLE); From ad20a07bb6ac33e76c26de4d08144753630a1eec Mon Sep 17 00:00:00 2001 From: Sandra G Date: Tue, 13 Feb 2024 10:55:24 -0500 Subject: [PATCH 02/15] [Infra] add services to host detail ui (#176539) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Closes https://github.com/elastic/kibana/issues/168641. - Adds a new UI component to the host detail in a new collapsible, 'Services'. On both the flyout and asset details page when viewing an asset of type host only, this component should exist and list related services to the host. - Removes "APM Services" link that used to exist in the detail view Screenshot 2024-02-09 at 12 26 15 PM ## Manual Testing ### Host with services - Go to the host view and find a host with services using the edge cluster, by opening the flyout of various hosts - Clicking on "show all" should take you to APM services inventory filtered by the host and showing the same services with time range persisted - Clicking on an individual service from the flyout should take you to the APM service overview with timerange persisted - Same should work on the node details ### Host with no services Screenshot 2024-02-09 at 6 02 12 PM - Go to the host view and find a host with no services using the edge cluster - Open the host flyout and there should be a message that no services were found - Same should work on the node details ### APM Services link removed The link seen below (top right) should not exist Screenshot 2024-02-09 at 5 51 11 PM --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../host_details/get_infra_services.ts | 6 +- .../context/fixtures/asset_details_props.ts | 2 +- .../components/section_titles.tsx | 13 +++ .../components/services_tooltip_content.tsx | 41 +++++++ .../asset_details/hooks/use_page_header.tsx | 3 +- .../asset_details/hooks/use_services.ts | 58 ++++++++++ .../links/link_to_apm_service.tsx | 54 +++++++++ .../links/link_to_apm_services.tsx | 6 +- .../asset_details/tabs/overview/overview.tsx | 8 +- .../asset_details/tabs/overview/services.tsx | 103 ++++++++++++++++++ .../public/components/asset_details/types.ts | 2 +- .../host_details_flyout/flyout_wrapper.tsx | 2 +- .../metric_detail/asset_detail_page.tsx | 1 - .../server/lib/host_details/get_services.ts | 34 +++++- x-pack/plugins/infra/tsconfig.json | 3 +- x-pack/test/functional/apps/infra/helpers.ts | 48 ++++++++ .../test/functional/apps/infra/hosts_view.ts | 80 +++++++++++--- .../functional/apps/infra/node_details.ts | 1 + .../functional/page_objects/asset_details.ts | 30 +++++ 19 files changed, 464 insertions(+), 31 deletions(-) create mode 100644 x-pack/plugins/infra/public/components/asset_details/components/services_tooltip_content.tsx create mode 100644 x-pack/plugins/infra/public/components/asset_details/hooks/use_services.ts create mode 100644 x-pack/plugins/infra/public/components/asset_details/links/link_to_apm_service.tsx create mode 100644 x-pack/plugins/infra/public/components/asset_details/tabs/overview/services.tsx create mode 100644 x-pack/test/functional/apps/infra/helpers.ts diff --git a/x-pack/plugins/infra/common/http_api/host_details/get_infra_services.ts b/x-pack/plugins/infra/common/http_api/host_details/get_infra_services.ts index 56b5a4757bdb2..718513416dad7 100644 --- a/x-pack/plugins/infra/common/http_api/host_details/get_infra_services.ts +++ b/x-pack/plugins/infra/common/http_api/host_details/get_infra_services.ts @@ -67,8 +67,8 @@ export const ServicesAPIQueryAggregationRT = rt.type({ export type ServicesAPIQueryAggregation = rt.TypeOf; export const ServiceRT = rt.type({ - 'service.name': rt.string, - 'agent.name': AgentNameRT, + serviceName: rt.string, + agentName: AgentNameRT, }); export type Service = rt.TypeOf; @@ -76,3 +76,5 @@ export type Service = rt.TypeOf; export const ServicesAPIResponseRT = rt.type({ services: rt.array(ServiceRT), }); + +export type ServicesAPIResponse = rt.TypeOf; diff --git a/x-pack/plugins/infra/public/components/asset_details/__stories__/context/fixtures/asset_details_props.ts b/x-pack/plugins/infra/public/components/asset_details/__stories__/context/fixtures/asset_details_props.ts index 9d6b4efb96ec2..8cca6dd66d027 100644 --- a/x-pack/plugins/infra/public/components/asset_details/__stories__/context/fixtures/asset_details_props.ts +++ b/x-pack/plugins/infra/public/components/asset_details/__stories__/context/fixtures/asset_details_props.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import { type AssetDetailsProps, ContentTabIds, type Tab } from '../../../types'; -const links: AssetDetailsProps['links'] = ['alertRule', 'nodeDetails', 'apmServices']; +const links: AssetDetailsProps['links'] = ['alertRule', 'nodeDetails']; const tabs: Tab[] = [ { id: ContentTabIds.OVERVIEW, diff --git a/x-pack/plugins/infra/public/components/asset_details/components/section_titles.tsx b/x-pack/plugins/infra/public/components/asset_details/components/section_titles.tsx index b1b083bf3f0b5..7067909d56ee9 100644 --- a/x-pack/plugins/infra/public/components/asset_details/components/section_titles.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/components/section_titles.tsx @@ -11,6 +11,7 @@ import { i18n } from '@kbn/i18n'; import { HostMetricsExplanationContent } from '../../lens'; import { Popover } from '../tabs/common/popover'; import { AlertsTooltipContent } from './alerts_tooltip_content'; +import { ServicesTooltipContent } from './services_tooltip_content'; const SectionTitle = ({ title, @@ -94,3 +95,15 @@ export const AlertsSectionTitle = () => { ); }; + +export const ServicesSectionTitle = () => ( + + + +); diff --git a/x-pack/plugins/infra/public/components/asset_details/components/services_tooltip_content.tsx b/x-pack/plugins/infra/public/components/asset_details/components/services_tooltip_content.tsx new file mode 100644 index 0000000000000..5efcfc1ea4f56 --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/components/services_tooltip_content.tsx @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiText, EuiLink } from '@elastic/eui'; +import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { useLinkProps } from '@kbn/observability-shared-plugin/public'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; + +export const ServicesTooltipContent = () => { + const { services } = useKibanaContextForPlugin(); + const linkProps = useLinkProps({ + app: 'home', + hash: '/tutorial/apm', + }); + return ( + + + + + + + ), + }} + /> + + ); +}; diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx b/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx index 905def3ab0bc0..fc4577227f615 100644 --- a/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx @@ -20,7 +20,7 @@ import { usePluginConfig } from '../../../containers/plugin_config_context'; import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useProfilingIntegrationSetting } from '../../../hooks/use_profiling_integration_setting'; import { APM_HOST_FILTER_FIELD } from '../constants'; -import { LinkToAlertsRule, LinkToApmServices, LinkToNodeDetails } from '../links'; +import { LinkToAlertsRule, LinkToNodeDetails } from '../links'; import { ContentTabIds, type LinkOptions, type RouteState, type Tab, type TabIds } from '../types'; import { useAssetDetailsRenderPropsContext } from './use_asset_details_render_props'; import { useTabSwitcherContext } from './use_tab_switcher'; @@ -96,7 +96,6 @@ const useRightSideItems = (links?: LinkOptions[]) => { ), alertRule: , - apmServices: , }), [asset.id, asset.name, asset.type] ); diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_services.ts b/x-pack/plugins/infra/public/components/asset_details/hooks/use_services.ts new file mode 100644 index 0000000000000..dae8203b37325 --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_services.ts @@ -0,0 +1,58 @@ +/* + * 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 { fold } from 'fp-ts/lib/Either'; +import { identity } from 'fp-ts/lib/function'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { useEffect, useMemo } from 'react'; +import { + ServicesAPIResponse, + ServicesAPIResponseRT, + ServicesAPIRequest, +} from '../../../../common/http_api/host_details'; +import { throwErrors, createPlainError } from '../../../../common/runtime_types'; +import { useHTTPRequest } from '../../../hooks/use_http_request'; +import { useRequestObservable } from './use_request_observable'; + +export function useServices(params: ServicesAPIRequest) { + const { request$ } = useRequestObservable(); + const decodeResponse = (response: any) => { + return pipe( + ServicesAPIResponseRT.decode(response), + fold(throwErrors(createPlainError), identity) + ); + }; + const fetchOptions = useMemo( + () => ({ query: { ...params, filters: JSON.stringify(params.filters) } }), + [params] + ); + const { error, loading, response, makeRequest } = useHTTPRequest( + `/api/infra/services`, + 'GET', + undefined, + decodeResponse, + undefined, + undefined, + true, + fetchOptions + ); + + useEffect(() => { + if (request$) { + request$.next(makeRequest); + } else { + makeRequest(); + } + }, [makeRequest, request$]); + + return { + error, + loading, + response, + makeRequest, + }; +} diff --git a/x-pack/plugins/infra/public/components/asset_details/links/link_to_apm_service.tsx b/x-pack/plugins/infra/public/components/asset_details/links/link_to_apm_service.tsx new file mode 100644 index 0000000000000..378697793d90b --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/links/link_to_apm_service.tsx @@ -0,0 +1,54 @@ +/* + * 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 { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; +import { EuiBadge, EuiText } from '@elastic/eui'; +import { AgentIcon } from '@kbn/custom-icons'; +import { AgentName } from '@kbn/elastic-agent-utils'; +import { i18n } from '@kbn/i18n'; +import { useLinkProps } from '@kbn/observability-shared-plugin/public'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; + +export interface LinkToApmServiceProps { + serviceName: string; + agentName: string | null; + dateRange: { from: string; to: string }; +} + +export const LinkToApmService = ({ serviceName, agentName, dateRange }: LinkToApmServiceProps) => { + const { services } = useKibanaContextForPlugin(); + + const linkProps = useLinkProps({ + app: 'apm', + pathname: `/services/${serviceName}/overview`, + search: { + rangeFrom: dateRange.from, + rangeTo: dateRange.to, + }, + }); + return ( + + + + {agentName ? ( + + ) : null} + {serviceName} + + + + ); +}; diff --git a/x-pack/plugins/infra/public/components/asset_details/links/link_to_apm_services.tsx b/x-pack/plugins/infra/public/components/asset_details/links/link_to_apm_services.tsx index 59cd4ca72ef1e..a7a70d1466ac9 100644 --- a/x-pack/plugins/infra/public/components/asset_details/links/link_to_apm_services.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/links/link_to_apm_services.tsx @@ -34,14 +34,16 @@ export const LinkToApmServices = ({ assetName, apmField }: LinkToApmServicesProp return ( diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx index 29dcdec3ddbc3..4af9aa8ddae78 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx @@ -22,6 +22,7 @@ import { SectionSeparator } from './section_separator'; import { MetadataErrorCallout } from '../../components/metadata_error_callout'; import { useIntersectingState } from '../../hooks/use_intersecting_state'; import { CpuProfilingPrompt } from './kpis/cpu_profiling_prompt'; +import { ServicesContent } from './services'; export const Overview = () => { const ref = useRef(null); @@ -32,7 +33,6 @@ export const Overview = () => { loading: metadataLoading, error: fetchMetadataError, } = useMetadataStateContext(); - const { logs, metrics } = useDataViewsContext(); const isFullPageView = renderMode.mode !== 'flyout'; @@ -78,6 +78,12 @@ export const Overview = () => { /> + {asset.type === 'host' ? ( + + + + + ) : null} {metricsSection} ); diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/services.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/services.tsx new file mode 100644 index 0000000000000..e1caec807e8f8 --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/services.tsx @@ -0,0 +1,103 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiCallOut, EuiLink } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import type { TimeRange } from '@kbn/es-query'; +import { useLinkProps } from '@kbn/observability-shared-plugin/public'; +import { CollapsibleSection } from './section/collapsible_section'; +import { ServicesSectionTitle } from '../../components/section_titles'; +import { useServices } from '../../hooks/use_services'; +import { HOST_FIELD } from '../../../../../common/constants'; +import { LinkToApmServices } from '../../links'; +import { APM_HOST_FILTER_FIELD } from '../../constants'; +import { LinkToApmService } from '../../links/link_to_apm_service'; + +export const ServicesContent = ({ + hostName, + dateRange, +}: { + hostName: string; + dateRange: TimeRange; +}) => { + const linkProps = useLinkProps({ + app: 'home', + hash: '/tutorial/apm', + }); + const params = useMemo( + () => ({ + filters: { [HOST_FIELD]: hostName }, + from: dateRange.from, + to: dateRange.to, + }), + [hostName, dateRange.from, dateRange.to] + ); + const { error, loading, response } = useServices(params); + const services = response?.services; + const hasServices = services?.length; + + return ( + } + > + {error ? ( + + {i18n.translate('xpack.infra.assetDetails.services.getServicesRequestError', { + defaultMessage: 'An error occurred while fetching services.', + })} + + ) : loading ? ( + + ) : hasServices ? ( + + {services.map((service, index) => ( + + + + ))} + + ) : ( +

+ + + + ), + }} + /> +

+ )} +
+ ); +}; diff --git a/x-pack/plugins/infra/public/components/asset_details/types.ts b/x-pack/plugins/infra/public/components/asset_details/types.ts index 346eda2bb3c32..03ae24810e217 100644 --- a/x-pack/plugins/infra/public/components/asset_details/types.ts +++ b/x-pack/plugins/infra/public/components/asset_details/types.ts @@ -63,7 +63,7 @@ export interface Tab { append?: JSX.Element; } -export type LinkOptions = 'alertRule' | 'nodeDetails' | 'apmServices'; +export type LinkOptions = 'alertRule' | 'nodeDetails'; export interface AssetDetailsProps { assetId: string; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/flyout_wrapper.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/flyout_wrapper.tsx index c377eb5043c79..77a929988f493 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/flyout_wrapper.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/flyout_wrapper.tsx @@ -33,7 +33,7 @@ export const FlyoutWrapper = ({ node: { name }, closeFlyout }: Props) => { }, }} tabs={commonFlyoutTabs} - links={['apmServices', 'nodeDetails']} + links={['nodeDetails']} renderMode={{ mode: 'flyout', closeFlyout, diff --git a/x-pack/plugins/infra/public/pages/metrics/metric_detail/asset_detail_page.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/asset_detail_page.tsx index 81f577f1d553f..7414d2ab4bf93 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metric_detail/asset_detail_page.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/asset_detail_page.tsx @@ -65,7 +65,6 @@ export const AssetDetailPage = () => { assetId={nodeId} assetType={nodeType} tabs={commonFlyoutTabs} - links={['apmServices']} renderMode={{ mode: 'page', }} diff --git a/x-pack/plugins/infra/server/lib/host_details/get_services.ts b/x-pack/plugins/infra/server/lib/host_details/get_services.ts index f2a58cf72d4de..e037889e4fece 100644 --- a/x-pack/plugins/infra/server/lib/host_details/get_services.ts +++ b/x-pack/plugins/infra/server/lib/host_details/get_services.ts @@ -8,6 +8,7 @@ import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { APMDataAccessConfig } from '@kbn/apm-data-access-plugin/server'; import { termQuery } from '@kbn/observability-plugin/server'; +import { PROCESSOR_EVENT } from '@kbn/observability-shared-plugin/common/field_names/elasticsearch'; import { ESSearchClient } from '../metrics/types'; import { ServicesAPIRequest, @@ -79,12 +80,35 @@ export const getServices = async ( filter: [ { term: { - 'metricset.name': 'transaction', + [PROCESSOR_EVENT]: 'metric', }, }, { - term: { - 'metricset.interval': '1m', // make this dynamic if we start returning time series data + bool: { + should: [ + { + term: { + 'metricset.name': 'app', + }, + }, + { + bool: { + must: [ + { + term: { + 'metricset.name': 'transaction', + }, + }, + { + term: { + 'metricset.interval': '1m', // make this dynamic if we start returning time series data + }, + }, + ], + }, + }, + ], + minimum_should_match: 1, }, }, ...commonFiltersList, @@ -136,8 +160,8 @@ export const getServices = async ( const services = Array.from(serviceMap) .slice(0, size) .map(([serviceName, { agentName }]) => ({ - 'service.name': serviceName, - 'agent.name': agentName, + serviceName, + agentName, })); return { services }; }; diff --git a/x-pack/plugins/infra/tsconfig.json b/x-pack/plugins/infra/tsconfig.json index fcda9c0de77a1..5a12a83b5fd58 100644 --- a/x-pack/plugins/infra/tsconfig.json +++ b/x-pack/plugins/infra/tsconfig.json @@ -85,7 +85,8 @@ "@kbn/management-settings-components-field-row", "@kbn/core-ui-settings-browser", "@kbn/core-saved-objects-api-server", - "@kbn/securitysolution-io-ts-utils" + "@kbn/securitysolution-io-ts-utils", + "@kbn/elastic-agent-utils" ], "exclude": ["target/**/*"] } diff --git a/x-pack/test/functional/apps/infra/helpers.ts b/x-pack/test/functional/apps/infra/helpers.ts new file mode 100644 index 0000000000000..51356acadf146 --- /dev/null +++ b/x-pack/test/functional/apps/infra/helpers.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { apm, timerange } from '@kbn/apm-synthtrace-client'; + +const SERVICE_PREFIX = 'service'; +// generates traces, metrics for services +export function generateAddServicesToExistingHost({ + from, + to, + hostName, + servicesPerHost = 1, +}: { + from: string; + to: string; + hostName: string; + servicesPerHost?: number; +}) { + const range = timerange(from, to); + const services = Array(servicesPerHost) + .fill(null) + .map((_, serviceIdx) => + apm + .service({ + name: `${SERVICE_PREFIX}-${serviceIdx}`, + environment: 'production', + agentName: 'nodejs', + }) + .instance(hostName) + ); + + return range + .interval('1m') + .rate(1) + .generator((timestamp, index) => + services.map((service) => + service + .transaction({ transactionName: 'GET /foo' }) + .timestamp(timestamp) + .duration(500) + .success() + ) + ); +} diff --git a/x-pack/test/functional/apps/infra/hosts_view.ts b/x-pack/test/functional/apps/infra/hosts_view.ts index 96a258303eb30..9742eed4d2f30 100644 --- a/x-pack/test/functional/apps/infra/hosts_view.ts +++ b/x-pack/test/functional/apps/infra/hosts_view.ts @@ -7,7 +7,14 @@ import moment from 'moment'; import expect from '@kbn/expect'; -import { parse } from 'url'; +import { + ApmSynthtraceEsClient, + ApmSynthtraceKibanaClient, + createLogger, + LogLevel, +} from '@kbn/apm-synthtrace'; +import url from 'url'; +import { kbnTestConfig } from '@kbn/test'; import { enableInfrastructureHostsView } from '@kbn/observability-plugin/common'; import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED } from '@kbn/rule-data-utils'; import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; @@ -18,6 +25,7 @@ import { HOSTS_VIEW_PATH, DATE_PICKER_FORMAT, } from './constants'; +import { generateAddServicesToExistingHost } from './helpers'; const START_DATE = moment.utc(DATES.metricsAndLogs.hosts.min); const END_DATE = moment.utc(DATES.metricsAndLogs.hosts.max); @@ -90,6 +98,7 @@ const tableEntries = [ export default ({ getPageObjects, getService }: FtrProviderContext) => { const browser = getService('browser'); const esArchiver = getService('esArchiver'); + const esClient = getService('es'); const find = getService('find'); const kibanaServer = getService('kibanaServer'); const observability = getService('observability'); @@ -107,6 +116,18 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ]); // Helpers + + const getKibanaServerUrl = () => { + const kibanaServerUrl = url.format(kbnTestConfig.getUrlParts() as url.UrlObject); + const kibanaServerUrlWithAuth = url + .format({ + ...url.parse(kibanaServerUrl), + auth: `elastic:${kbnTestConfig.getUrlParts().password}`, + }) + .slice(0, -1); + return kibanaServerUrlWithAuth; + }; + const setHostViewEnabled = (value: boolean = true) => kibanaServer.uiSettings.update({ [enableInfrastructureHostsView]: value }); @@ -127,8 +148,29 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ); describe('Hosts View', function () { + let synthtraceApmClient: any; before(async () => { + const kibanaClient = new ApmSynthtraceKibanaClient({ + target: getKibanaServerUrl(), + logger: createLogger(LogLevel.debug), + }); + const kibanaVersion = await kibanaClient.fetchLatestApmPackageVersion(); + await kibanaClient.installApmPackage(kibanaVersion); + synthtraceApmClient = new ApmSynthtraceEsClient({ + client: esClient, + logger: createLogger(LogLevel.info), + version: kibanaVersion, + refreshAfterIndex: true, + }); await Promise.all([ + synthtraceApmClient.index( + generateAddServicesToExistingHost({ + from: DATES.metricsAndLogs.hosts.processesDataStartDate, + to: DATES.metricsAndLogs.hosts.processesDataEndDate, + hostName: 'Jennys-MBP.fritz.box', + servicesPerHost: 3, + }) + ), esArchiver.load('x-pack/test/functional/es_archives/infra/alerts'), esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'), esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_hosts_processes'), @@ -139,6 +181,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { after(async () => { await Promise.all([ + synthtraceApmClient.clean(), esArchiver.unload('x-pack/test/functional/es_archives/infra/alerts'), esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'), esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_hosts_processes'), @@ -209,16 +252,37 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(hosts.length).to.equal(9); }); - it('should show all section as collapsable', async () => { + it('should show all section as collapsible', async () => { await pageObjects.assetDetails.metadataSectionCollapsibleExist(); await pageObjects.assetDetails.alertsSectionCollapsibleExist(); await pageObjects.assetDetails.metricsSectionCollapsibleExist(); + await pageObjects.assetDetails.servicesSectionCollapsibleExist(); }); it('should show alerts', async () => { await pageObjects.header.waitUntilLoadingHasFinished(); await pageObjects.assetDetails.overviewAlertsTitleExists(); }); + + it('should show 3 services each with an icon, service name, and url', async () => { + await pageObjects.assetDetails.servicesSectionCollapsibleExist(); + + const services = + await pageObjects.assetDetails.getAssetDetailsServicesWithIconsAndNames(); + + expect(services.length).to.equal(3); + + const currentUrl = await browser.getCurrentUrl(); + const parsedUrl = new URL(currentUrl); + const baseUrl = `${parsedUrl.protocol}//${parsedUrl.host}`; + + services.forEach((service, index) => { + expect(service.serviceName).to.equal(`service-${index}`); + expect(service.iconSrc).to.not.be.empty(); + const expectedUrlPattern = `${baseUrl}/app/apm/services/service-${index}/overview?rangeFrom=${DATES.metricsAndLogs.hosts.processesDataStartDate}&rangeTo=${DATES.metricsAndLogs.hosts.processesDataEndDate}`; + expect(service.serviceUrl).to.equal(expectedUrlPattern); + }); + }); }); describe('Metadata Tab', () => { @@ -270,18 +334,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); describe('Flyout links', () => { - it('should navigate to APM services after click', async () => { - await pageObjects.assetDetails.clickApmServicesLink(); - 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); - }); - it('should navigate to Host Details page after click', async () => { await pageObjects.assetDetails.clickOpenAsPageLink(); const dateRange = await pageObjects.timePicker.getTimeConfigAsAbsoluteTimes(); diff --git a/x-pack/test/functional/apps/infra/node_details.ts b/x-pack/test/functional/apps/infra/node_details.ts index 42147652f34a5..f79ac8a00d771 100644 --- a/x-pack/test/functional/apps/infra/node_details.ts +++ b/x-pack/test/functional/apps/infra/node_details.ts @@ -197,6 +197,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.assetDetails.metadataSectionCollapsibleExist(); await pageObjects.assetDetails.alertsSectionCollapsibleExist(); await pageObjects.assetDetails.metricsSectionCollapsibleExist(); + await pageObjects.assetDetails.servicesSectionCollapsibleExist(); }); it('should show alerts', async () => { diff --git a/x-pack/test/functional/page_objects/asset_details.ts b/x-pack/test/functional/page_objects/asset_details.ts index cd34d9c2ca10b..a0e13e23d7570 100644 --- a/x-pack/test/functional/page_objects/asset_details.ts +++ b/x-pack/test/functional/page_objects/asset_details.ts @@ -43,6 +43,33 @@ export function AssetDetailsProvider({ getService }: FtrProviderContext) { ); }, + async getAssetDetailsServicesWithIconsAndNames() { + await testSubjects.existOrFail('infraAssetDetailsServicesContainer'); + const container = await testSubjects.find('infraAssetDetailsServicesContainer'); + const serviceLinks = await container.findAllByCssSelector('[data-test-subj="serviceLink"]'); + + const servicesWithIconsAndNames = await Promise.all( + serviceLinks.map(async (link, index) => { + const icon = await link.findByTagName('img'); + const iconSrc = await icon.getAttribute('src'); + await testSubjects.existOrFail(`serviceNameText-service-${index}`); + const serviceElement = await link.findByCssSelector( + `[data-test-subj="serviceNameText-service-${index}"]` + ); + const serviceName = await serviceElement.getVisibleText(); + const serviceUrl = await link.getAttribute('href'); + + return { + serviceName, + serviceUrl, + iconSrc, + }; + }) + ); + + return servicesWithIconsAndNames; + }, + async getAssetDetailsKubernetesMetricsCharts() { const container = await testSubjects.find('infraAssetDetailsKubernetesMetricsChartGrid'); return container.findAllByCssSelector( @@ -85,6 +112,9 @@ export function AssetDetailsProvider({ getService }: FtrProviderContext) { async alertsSectionCollapsibleExist() { return await testSubjects.existOrFail('infraAssetDetailsAlertsCollapsible'); }, + async servicesSectionCollapsibleExist() { + return await testSubjects.existOrFail('infraAssetDetailsServicesCollapsible'); + }, async metricsSectionCollapsibleExist() { return await testSubjects.existOrFail('infraAssetDetailsMetricsCollapsible'); }, From fbc0586c8c3e526bd14533858ecc7b3d615f43cd Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 13 Feb 2024 15:57:15 +0000 Subject: [PATCH 03/15] skip flaky suite (#175204) --- .../cases/public/components/create/description.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/components/create/description.test.tsx b/x-pack/plugins/cases/public/components/create/description.test.tsx index d0426731f97d9..f3fd7342db17e 100644 --- a/x-pack/plugins/cases/public/components/create/description.test.tsx +++ b/x-pack/plugins/cases/public/components/create/description.test.tsx @@ -17,7 +17,8 @@ import { MAX_DESCRIPTION_LENGTH } from '../../../common/constants'; import { FormTestComponent } from '../../common/test_utils'; import type { FormSchema } from '@kbn/index-management-plugin/public/shared_imports'; -describe('Description', () => { +// FLAKY: https://github.com/elastic/kibana/issues/175204 +describe.skip('Description', () => { let appMockRender: AppMockRenderer; const onSubmit = jest.fn(); const draftStorageKey = `cases.caseView.createCase.description.markdownEditor`; From 2d51f0bb412894652191f2650b54295513a002f4 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 13 Feb 2024 16:07:44 +0000 Subject: [PATCH 04/15] skip flaky suite (#176119) --- .../tests/correlations/field_candidates.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/apm_api_integration/tests/correlations/field_candidates.spec.ts b/x-pack/test/apm_api_integration/tests/correlations/field_candidates.spec.ts index 448f90b1228b4..1984f7f652c27 100644 --- a/x-pack/test/apm_api_integration/tests/correlations/field_candidates.spec.ts +++ b/x-pack/test/apm_api_integration/tests/correlations/field_candidates.spec.ts @@ -37,7 +37,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - registry.when( + // FLAKY: https://github.com/elastic/kibana/issues/176119 + registry.when.skip( 'field candidates with data and default args', { config: 'trial', archives: ['8.0.0'] }, () => { From a52cddc072e08a1c29d19bb6c5bcea4cb47a9b14 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 13 Feb 2024 16:09:11 +0000 Subject: [PATCH 05/15] skip flaky suite (#175601) --- .../functional/test_suites/search/default_dataview.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test_serverless/functional/test_suites/search/default_dataview.ts b/x-pack/test_serverless/functional/test_suites/search/default_dataview.ts index 2beb234f688f4..0a0212ba10919 100644 --- a/x-pack/test_serverless/functional/test_suites/search/default_dataview.ts +++ b/x-pack/test_serverless/functional/test_suites/search/default_dataview.ts @@ -13,7 +13,8 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { const svlCommonNavigation = getPageObject('svlCommonNavigation'); const svlCommonPage = getPageObject('svlCommonPage'); - describe('default dataView', function () { + // FLAKY: https://github.com/elastic/kibana/issues/175601 + describe.skip('default dataView', function () { // Error: expected testSubject(kbnOverviewElasticsearchGettingStarted) to exist this.tags(['failsOnMKI']); before(async () => { From 557ab3c1a50fd5c23577e0ac8cae4d19bda46bc3 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 13 Feb 2024 16:11:53 +0000 Subject: [PATCH 06/15] skip flaky suite (#176529) --- .../assignments/assignments_serverless_essentials.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/detection_alerts/assignments/assignments_serverless_essentials.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/detection_alerts/assignments/assignments_serverless_essentials.cy.ts index f8bbf2620a542..0405fb7dc5976 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/detection_alerts/assignments/assignments_serverless_essentials.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/detection_alerts/assignments/assignments_serverless_essentials.cy.ts @@ -20,7 +20,8 @@ import { loadPageAs, } from '../../../../../tasks/alert_assignments'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/176529 +describe.skip( 'Alert user assignment - Serverless Essentials', { tags: ['@serverless'], From 8a120ebfb60a89cbcbdf00422bd822dc348a63c9 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 13 Feb 2024 16:13:19 +0000 Subject: [PATCH 07/15] skip flaky suite (#175608) --- .../functional/test_suites/security/ftr/navigation.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 69bc9d517e7e8..fc75dab7160f5 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 @@ -19,7 +19,8 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { const headerPage = getPageObject('header'); const retry = getService('retry'); - describe('navigation', function () { + // FLAKY: https://github.com/elastic/kibana/issues/175608 + describe.skip('navigation', function () { before(async () => { await svlCommonPage.login(); await svlSecNavigation.navigateToLandingPage(); From c6b1c75f931730afba5b1f7138229ba13e5f85c3 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 13 Feb 2024 16:16:00 +0000 Subject: [PATCH 08/15] skip flaky suite (#176643) --- .../public/components/user_profiles/user_tooltip.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/components/user_profiles/user_tooltip.test.tsx b/x-pack/plugins/cases/public/components/user_profiles/user_tooltip.test.tsx index d105cc1db0053..5fdf94f96c266 100644 --- a/x-pack/plugins/cases/public/components/user_profiles/user_tooltip.test.tsx +++ b/x-pack/plugins/cases/public/components/user_profiles/user_tooltip.test.tsx @@ -10,7 +10,8 @@ import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import React from 'react'; import { UserToolTip } from './user_tooltip'; -describe('UserToolTip', () => { +// FLAKY: https://github.com/elastic/kibana/issues/176643 +describe.skip('UserToolTip', () => { it('renders the tooltip when hovering', async () => { const profile: UserProfileWithAvatar = { uid: '1', From 2632379fc94c93a45c2dc0e430c733a9c94349f7 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 13 Feb 2024 16:43:23 +0000 Subject: [PATCH 09/15] fix(NA): import for deleteAllRules on detections response api integration tests --- .../trial_license_complete_tier/import_connectors.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_connectors.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_connectors.ts index 89af5bb0987ed..70a1a42817574 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_connectors.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_connectors.ts @@ -8,7 +8,8 @@ import expect from 'expect'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; -import { combineToNdJson, deleteAllRules, getCustomQueryRuleParams } from '../../../utils'; +import { combineToNdJson, getCustomQueryRuleParams } from '../../../utils'; +import { deleteAllRules } from '../../../../../../common/utils/security_solution'; import { createConnector, deleteConnector, getConnector } from '../../../utils/connectors'; import { FtrProviderContext } from '../../../../../ftr_provider_context'; From 207d844b94b66b45bf911eec9a14abee63f4a79c Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 13 Feb 2024 16:49:47 +0000 Subject: [PATCH 10/15] skip flaky suite (#176336) --- .../cases/public/components/all_cases/severity_filter.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/components/all_cases/severity_filter.test.tsx b/x-pack/plugins/cases/public/components/all_cases/severity_filter.test.tsx index ca09d53501e5f..66b808dca5591 100644 --- a/x-pack/plugins/cases/public/components/all_cases/severity_filter.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/severity_filter.test.tsx @@ -14,7 +14,8 @@ import { screen, waitFor } from '@testing-library/react'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; import { SeverityFilter } from './severity_filter'; -describe('Severity form field', () => { +// FLAKY: https://github.com/elastic/kibana/issues/176336 +describe.skip('Severity form field', () => { const onChange = jest.fn(); let appMockRender: AppMockRenderer; const props = { From 41918cad5313e2401c04541e4ec781bd232e9197 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 13 Feb 2024 16:51:34 +0000 Subject: [PATCH 11/15] skip flaky suite (#176836) --- .../trial_license_complete_tier/import_connectors.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_connectors.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_connectors.ts index 70a1a42817574..d6c7b3f8ede86 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_connectors.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_import_export/trial_license_complete_tier/import_connectors.ts @@ -17,7 +17,8 @@ export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); const log = getService('log'); - describe('@ess @brokenInServerless @skipInQA import action connectors', () => { + // FLAKY: https://github.com/elastic/kibana/issues/176836 + describe.skip('@ess @brokenInServerless @skipInQA import action connectors', () => { const CONNECTOR_ID = '1be16246-642a-4ed8-bfd3-b47f8c7d7055'; const ANOTHER_CONNECTOR_ID = 'abc16246-642a-4ed8-bfd3-b47f8c7d7055'; const CUSTOM_ACTION_CONNECTOR = { From 6006c96461d1820280c943622ceac669dfd3798e Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 13 Feb 2024 16:53:12 +0000 Subject: [PATCH 12/15] skip flaky suite (#174384) --- .../registered_attachments_property_actions.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/registered_attachments_property_actions.test.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/registered_attachments_property_actions.test.tsx index f0db59b3a682d..680139573a13a 100644 --- a/x-pack/plugins/cases/public/components/user_actions/property_actions/registered_attachments_property_actions.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/registered_attachments_property_actions.test.tsx @@ -18,7 +18,8 @@ import { import { RegisteredAttachmentsPropertyActions } from './registered_attachments_property_actions'; import { AttachmentActionType } from '../../../client/attachment_framework/types'; -describe('RegisteredAttachmentsPropertyActions', () => { +// FLAKY: https://github.com/elastic/kibana/issues/174384 +describe.skip('RegisteredAttachmentsPropertyActions', () => { let appMock: AppMockRenderer; const props = { From 32e3173063af95fbc2c5640e2a2c5954e1d82e45 Mon Sep 17 00:00:00 2001 From: Umberto Pepato Date: Tue, 13 Feb 2024 17:55:56 +0100 Subject: [PATCH 13/15] [RAM] Improve default AlertsTable columns configuration (#176137) ## Summary Adds the new columns described in #174279 to the default AlertsTable configuration. --- .../alerts_table/cells/render_cell_value.tsx | 40 +++++++++- .../sections/alerts_table/configuration.tsx | 73 ++++++++++++++++--- 2 files changed, 101 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/cells/render_cell_value.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/cells/render_cell_value.tsx index 28ef1439c8849..9c1f2c4345553 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/cells/render_cell_value.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/cells/render_cell_value.tsx @@ -7,12 +7,19 @@ import { isEmpty } from 'lodash'; import React, { type ReactNode } from 'react'; -import { ALERT_DURATION, TIMESTAMP } from '@kbn/rule-data-utils'; +import { + ALERT_DURATION, + ALERT_RULE_NAME, + ALERT_RULE_UUID, + ALERT_START, + TIMESTAMP, +} from '@kbn/rule-data-utils'; import { FIELD_FORMAT_IDS, FieldFormatParams, FieldFormatsRegistry, } from '@kbn/field-formats-plugin/common'; +import { EuiLink } from '@elastic/eui'; import { GetRenderCellValue } from '../../../../types'; import { useKibana } from '../../../../common/lib/kibana'; @@ -62,7 +69,7 @@ export const getRenderCellValue = (fieldFormats: FieldFormatsRegistry): GetRende }); const value = getRenderValue(mappedNonEcsValue); - return alertValueFormatter(columnId, value); + return alertValueFormatter(columnId, value, data); }; }; @@ -91,13 +98,40 @@ export function useFieldFormatter(fieldType: FIELD_FORMAT_IDS) { return getFieldFormatterProvider(fieldFormats as FieldFormatsRegistry)(fieldType); } +const AlertRuleLink = ({ alertFields }: { alertFields: Array<{ field: string; value: any }> }) => { + const { http } = useKibana().services; + const ruleName = alertFields.find((f) => f.field === ALERT_RULE_NAME)?.value?.[0]; + const ruleUuid = alertFields.find((f) => f.field === ALERT_RULE_UUID)?.value?.[0]; + + if (!ruleName || !ruleUuid) { + return null; + } + + return ( + + {ruleName} + + ); +}; + export function getAlertFormatters(fieldFormats: FieldFormatsRegistry) { const getFormatter = getFieldFormatterProvider(fieldFormats); - return (columnId: string, value: any): React.ReactElement => { + return ( + columnId: string, + value: any, + rowData?: Array<{ field: string; value: any }> + ): React.ReactElement => { switch (columnId) { case TIMESTAMP: + case ALERT_START: return <>{getFormatter(FIELD_FORMAT_IDS.DATE)(value)}; + case ALERT_RULE_NAME: + return rowData ? : <>{value}; case ALERT_DURATION: return ( <> diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/configuration.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/configuration.tsx index 4151e366e9257..6cd342b2de2bc 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/configuration.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/configuration.tsx @@ -7,13 +7,17 @@ import React from 'react'; import { - ALERT_DURATION, + ALERT_EVALUATION_THRESHOLD, + ALERT_EVALUATION_VALUES, ALERT_MAINTENANCE_WINDOW_IDS, ALERT_REASON, + ALERT_RULE_CATEGORY, + ALERT_RULE_NAME, + ALERT_RULE_TAGS, + ALERT_START, ALERT_STATUS, TIMESTAMP, } from '@kbn/rule-data-utils'; -import { SortOrder } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { FieldFormatsRegistry } from '@kbn/field-formats-plugin/common'; import { i18n } from '@kbn/i18n'; import { getDefaultAlertFlyout } from './alerts_flyout/default_alerts_flyout'; @@ -29,7 +33,7 @@ const columns = [ defaultMessage: 'Alert Status', }), id: ALERT_STATUS, - initialWidth: 110, + initialWidth: 120, }, { columnHeaderType: 'not-filtered', @@ -40,16 +44,66 @@ const columns = [ } ), id: TIMESTAMP, - initialWidth: 230, + initialWidth: 200, + schema: 'datetime', + }, + { + columnHeaderType: 'not-filtered', + displayAsText: i18n.translate('xpack.triggersActionsUI.alertsTable.startedColumnDescription', { + defaultMessage: 'Started', + }), + id: ALERT_START, + initialWidth: 200, schema: 'datetime', }, { columnHeaderType: 'not-filtered', - displayAsText: i18n.translate('xpack.triggersActionsUI.alertsTable.durationColumnDescription', { - defaultMessage: 'Duration', + displayAsText: i18n.translate( + 'xpack.triggersActionsUI.alertsTable.ruleCategoryColumnDescription', + { + defaultMessage: 'Rule category', + } + ), + id: ALERT_RULE_CATEGORY, + initialWidth: 160, + }, + { + columnHeaderType: 'not-filtered', + displayAsText: i18n.translate('xpack.triggersActionsUI.alertsTable.ruleColumnDescription', { + defaultMessage: 'Rule', + }), + id: ALERT_RULE_NAME, + initialWidth: 230, + }, + { + columnHeaderType: 'not-filtered', + displayAsText: i18n.translate('xpack.triggersActionsUI.alertsTable.ruleTagsColumnDescription', { + defaultMessage: 'Rule tags', }), - id: ALERT_DURATION, - initialWidth: 116, + id: ALERT_RULE_TAGS, + initialWidth: 120, + }, + { + columnHeaderType: 'not-filtered', + displayAsText: i18n.translate( + 'xpack.triggersActionsUI.alertsTable.evaluationValuesColumnDescription', + { + defaultMessage: 'Evaluation values', + } + ), + id: ALERT_EVALUATION_VALUES, + initialWidth: 120, + }, + { + columnHeaderType: 'not-filtered', + displayAsText: i18n.translate( + 'xpack.triggersActionsUI.alertsTable.evaluationThresholdColumnDescription', + { + defaultMessage: 'Evaluation threshold', + } + ), + id: ALERT_EVALUATION_THRESHOLD, + initialWidth: 120, }, { columnHeaderType: 'not-filtered', @@ -58,6 +112,7 @@ const columns = [ }), id: ALERT_REASON, linkField: '*', + initialWidth: 260, }, { columnHeaderType: 'not-filtered', @@ -84,7 +139,7 @@ export const getAlertsTableConfiguration = ( sort: [ { [TIMESTAMP]: { - order: 'desc' as SortOrder, + order: 'desc', }, }, ], From dac930243b1b1331468d091678f0c176b1d080fc Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Tue, 13 Feb 2024 16:57:53 +0000 Subject: [PATCH 14/15] [Cases] Fix UserActionsList flaky tests (#176807) ## Summary Fixes https://github.com/elastic/kibana/issues/176525 Fixes https://github.com/elastic/kibana/issues/176524 ### 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 ### 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) --- .../user_actions/user_actions_list.test.tsx | 43 ++++++++----------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/cases/public/components/user_actions/user_actions_list.test.tsx b/x-pack/plugins/cases/public/components/user_actions/user_actions_list.test.tsx index 8e042c1b95a72..f8f04e9c77fb5 100644 --- a/x-pack/plugins/cases/public/components/user_actions/user_actions_list.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/user_actions_list.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { waitFor, screen } from '@testing-library/react'; +import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; // eslint-disable-next-line @kbn/eslint/module_migration import routeData from 'react-router'; @@ -31,9 +31,7 @@ const defaultProps = { jest.mock('../../common/lib/kibana'); -// FLAKY: https://github.com/elastic/kibana/issues/176524 -// FLAKY: https://github.com/elastic/kibana/issues/176525 -describe.skip(`UserActionsList`, () => { +describe(`UserActionsList`, () => { let appMockRender: AppMockRenderer; beforeEach(() => { @@ -46,27 +44,21 @@ describe.skip(`UserActionsList`, () => { it('renders list correctly with isExpandable option', async () => { appMockRender.render(); - await waitFor(() => { - expect(screen.getByTestId('user-actions-list')).toBeInTheDocument(); - }); + expect(await screen.findByTestId('user-actions-list')).toBeInTheDocument(); }); it('renders list correctly with isExpandable=false option', async () => { appMockRender.render(); - await waitFor(() => { - expect(screen.getByTestId('user-actions-list')).toBeInTheDocument(); - }); + expect(await screen.findByTestId('user-actions-list')).toBeInTheDocument(); }); it('renders user actions correctly', async () => { appMockRender.render(); - await waitFor(() => { - expect(screen.getByTestId(`description-create-action-${caseUserActions[0].id}`)); - expect(screen.getByTestId(`comment-create-action-${caseUserActions[1].commentId}`)); - expect(screen.getByTestId(`description-update-action-${caseUserActions[2].id}`)); - }); + expect(await screen.findByTestId(`description-create-action-${caseUserActions[0].id}`)); + expect(await screen.findByTestId(`comment-create-action-${caseUserActions[1].commentId}`)); + expect(await screen.findByTestId(`description-update-action-${caseUserActions[2].id}`)); }); it('renders bottom actions correctly', async () => { @@ -82,12 +74,11 @@ describe.skip(`UserActionsList`, () => { children: {sample}, }, ]; + appMockRender.render(); - await waitFor(() => { - expect(screen.getByTestId('user-actions-list')).toBeInTheDocument(); - expect(screen.getByTestId('add-comment')).toBeInTheDocument(); - }); + expect(await screen.findByTestId('user-actions-list')).toBeInTheDocument(); + expect(await screen.findByTestId('add-comment')).toBeInTheDocument(); }); it('Outlines comment when url param is provided', async () => { @@ -121,18 +112,18 @@ describe.skip(`UserActionsList`, () => { appMockRender.render(); expect( - screen - .queryAllByTestId(`comment-create-action-${props.data.comments[0].id}`)[0] - ?.classList.contains('outlined') + ( + await screen.findAllByTestId(`comment-create-action-${props.data.comments[0].id}`) + )[0]?.classList.contains('outlined') ).toBe(false); expect( - screen - .queryAllByTestId(`comment-create-action-${props.data.comments[0].id}`)[0] - ?.classList.contains('outlined') + ( + await screen.findAllByTestId(`comment-create-action-${props.data.comments[0].id}`) + )[0]?.classList.contains('outlined') ).toBe(false); - userEvent.click(screen.getByTestId(`comment-update-action-${ourActions[1].id}`)); + userEvent.click(await screen.findByTestId(`comment-update-action-${ourActions[1].id}`)); expect( await screen.findAllByTestId(`comment-create-action-${props.data.comments[0].id}`) From 789fe5634bce3fe682e8df190c8ec1a3468d82b1 Mon Sep 17 00:00:00 2001 From: Rodney Norris Date: Tue, 13 Feb 2024 11:00:45 -0600 Subject: [PATCH 15/15] [Search] introduce config feature flag for ai playground (#176755) ## Summary Introduce a config flag to hide development of the AI Playground page while in development. Usage of this flag will be added in a different PR. --- .../enterprise_search/common/__mocks__/initial_app_data.ts | 1 + x-pack/plugins/enterprise_search/common/constants.ts | 1 + x-pack/plugins/enterprise_search/common/types/index.ts | 2 ++ .../public/applications/test_helpers/test_utils.test_helper.tsx | 1 + x-pack/plugins/enterprise_search/server/index.ts | 2 ++ .../server/lib/enterprise_search_config_api.test.ts | 2 ++ .../server/lib/enterprise_search_config_api.ts | 2 ++ 7 files changed, 11 insertions(+) diff --git a/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts b/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts index 5ed2c6893be5f..957f2893540ce 100644 --- a/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts +++ b/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts @@ -38,6 +38,7 @@ export const DEFAULT_INITIAL_APP_DATA = { hasIncrementalSyncEnabled: true, hasNativeConnectors: true, hasWebCrawler: true, + showAIPlayground: false, }, appSearch: { accountId: 'some-id-string', diff --git a/x-pack/plugins/enterprise_search/common/constants.ts b/x-pack/plugins/enterprise_search/common/constants.ts index b338c331fef8e..f1f60450e3c4a 100644 --- a/x-pack/plugins/enterprise_search/common/constants.ts +++ b/x-pack/plugins/enterprise_search/common/constants.ts @@ -227,6 +227,7 @@ export const DEFAULT_PRODUCT_FEATURES: ProductFeatures = { hasIncrementalSyncEnabled: true, hasNativeConnectors: true, hasWebCrawler: true, + showAIPlayground: false, }; export const CONNECTORS_ACCESS_CONTROL_INDEX_PREFIX = '.search-acl-filter-'; diff --git a/x-pack/plugins/enterprise_search/common/types/index.ts b/x-pack/plugins/enterprise_search/common/types/index.ts index 38ac392884648..bbd14f9f968c8 100644 --- a/x-pack/plugins/enterprise_search/common/types/index.ts +++ b/x-pack/plugins/enterprise_search/common/types/index.ts @@ -43,6 +43,8 @@ export interface ProductFeatures { hasIncrementalSyncEnabled: boolean; hasNativeConnectors: boolean; hasWebCrawler: boolean; + // Temp Feature Flag for AI Playground page + showAIPlayground: boolean; } export interface SearchOAuth { diff --git a/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx b/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx index cab4a7c04b368..571cb0e092416 100644 --- a/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx @@ -73,6 +73,7 @@ export const mockKibanaProps: KibanaLogicProps = { hasIncrementalSyncEnabled: true, hasNativeConnectors: true, hasWebCrawler: true, + showAIPlayground: false, }, renderHeaderActions: jest.fn(), security: securityMock.createStart(), diff --git a/x-pack/plugins/enterprise_search/server/index.ts b/x-pack/plugins/enterprise_search/server/index.ts index 53d8cbca7f540..949c66cc37892 100644 --- a/x-pack/plugins/enterprise_search/server/index.ts +++ b/x-pack/plugins/enterprise_search/server/index.ts @@ -39,6 +39,8 @@ export const configSchema = schema.object({ ui: schema.object({ enabled: schema.boolean({ defaultValue: true }), }), + // Temp Feature Flag for AI Playground page + showAIPlayground: schema.boolean({ defaultValue: false }), }); export type ConfigType = TypeOf; diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts index fb17854f6f674..2b34ed6e3245f 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts @@ -211,6 +211,7 @@ describe('callEnterpriseSearchConfigAPI', () => { hasDefaultIngestPipeline: false, hasNativeConnectors: false, hasWebCrawler: false, + showAIPlayground: false, host: '', }; @@ -224,6 +225,7 @@ describe('callEnterpriseSearchConfigAPI', () => { hasDefaultIngestPipeline: false, hasNativeConnectors: false, hasWebCrawler: false, + showAIPlayground: false, }, kibanaVersion: '1.0.0', }); diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts index 90fccce31344b..1cfb6d033051f 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts @@ -56,6 +56,7 @@ export const callEnterpriseSearchConfigAPI = async ({ hasIncrementalSyncEnabled: config.hasIncrementalSyncEnabled, hasNativeConnectors: config.hasNativeConnectors, hasWebCrawler: config.hasWebCrawler, + showAIPlayground: config.showAIPlayground, }, kibanaVersion: kibanaPackageJson.version, }; @@ -111,6 +112,7 @@ export const callEnterpriseSearchConfigAPI = async ({ hasIncrementalSyncEnabled: config.hasIncrementalSyncEnabled, hasNativeConnectors: config.hasNativeConnectors, hasWebCrawler: config.hasWebCrawler, + showAIPlayground: config.showAIPlayground, }, publicUrl: stripTrailingSlash(data?.settings?.external_url), readOnlyMode: !!data?.settings?.read_only_mode,