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 = {
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`;
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 = {
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}`)
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',
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,
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/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',
},
},
],
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'] },
() => {
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');
},
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);
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..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
@@ -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';
@@ -16,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 = {
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'],
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 () => {
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();