diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/wrapper.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/wrapper.test.tsx
new file mode 100644
index 0000000000000..2df9978cee082
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/wrapper.test.tsx
@@ -0,0 +1,107 @@
+/*
+ * 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 { act, render } from '@testing-library/react';
+import type { PackageListItem } from '@kbn/fleet-plugin/common';
+import { installationStatuses } from '@kbn/fleet-plugin/common/constants';
+import {
+ CONTENT_TEST_ID,
+ DATA_VIEW_ERROR_TEST_ID,
+ DATA_VIEW_LOADING_PROMPT_TEST_ID,
+ SKELETON_TEST_ID,
+ Wrapper,
+} from './wrapper';
+import { useKibana } from '../../../common/lib/kibana';
+
+jest.mock('../../../common/lib/kibana');
+
+const packages: PackageListItem[] = [
+ {
+ id: 'splunk',
+ name: 'splunk',
+ status: installationStatuses.NotInstalled,
+ title: 'Splunk',
+ version: '',
+ },
+];
+
+describe('', () => {
+ it('should render a loading skeleton while creating the dataView', async () => {
+ (useKibana as jest.Mock).mockReturnValue({
+ services: {
+ data: {
+ dataViews: {
+ create: jest.fn(),
+ clearInstanceCache: jest.fn(),
+ },
+ },
+ },
+ });
+
+ await act(async () => {
+ const { getByTestId } = render();
+
+ expect(getByTestId(DATA_VIEW_LOADING_PROMPT_TEST_ID)).toBeInTheDocument();
+ expect(getByTestId(SKELETON_TEST_ID)).toBeInTheDocument();
+ });
+ });
+
+ it('should render an error if the dataView fail to be created correctly', async () => {
+ (useKibana as jest.Mock).mockReturnValue({
+ services: {
+ data: {
+ dataViews: {
+ create: jest.fn().mockReturnValue(undefined),
+ clearInstanceCache: jest.fn(),
+ },
+ },
+ },
+ });
+
+ jest.mock('react', () => ({
+ ...jest.requireActual('react'),
+ useEffect: jest.fn((f) => f()),
+ }));
+
+ await act(async () => {
+ const { getByTestId } = render();
+
+ await new Promise(process.nextTick);
+
+ expect(getByTestId(DATA_VIEW_LOADING_PROMPT_TEST_ID)).toBeInTheDocument();
+ expect(getByTestId(DATA_VIEW_ERROR_TEST_ID)).toHaveTextContent('Unable to create data view');
+ });
+ });
+
+ it('should render the content if the dataView is created correctly', async () => {
+ (useKibana as jest.Mock).mockReturnValue({
+ services: {
+ data: {
+ dataViews: {
+ create: jest.fn().mockReturnValue({ id: 'id' }),
+ clearInstanceCache: jest.fn(),
+ },
+ },
+ },
+ });
+
+ jest.mock('react', () => ({
+ ...jest.requireActual('react'),
+ useEffect: jest.fn((f) => f()),
+ }));
+
+ await act(async () => {
+ const { getByTestId } = render();
+
+ await new Promise(process.nextTick);
+
+ expect(getByTestId(DATA_VIEW_LOADING_PROMPT_TEST_ID)).toBeInTheDocument();
+ expect(getByTestId(CONTENT_TEST_ID)).toBeInTheDocument();
+ });
+ });
+});
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/wrapper.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/wrapper.tsx
index d6393d718dcd4..d12edd1f4c560 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/wrapper.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/wrapper.tsx
@@ -5,11 +5,29 @@
* 2.0.
*/
-import React, { memo } from 'react';
+import React, { memo, useEffect, useState } from 'react';
+import {
+ EuiEmptyPrompt,
+ EuiHorizontalRule,
+ EuiSkeletonLoading,
+ EuiSkeletonRectangle,
+ EuiSpacer,
+} from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import type { DataView, DataViewSpec } from '@kbn/data-views-plugin/common';
import type { PackageListItem } from '@kbn/fleet-plugin/common';
-import { EuiText } from '@elastic/eui';
+import { useKibana } from '../../../common/lib/kibana';
+
+const DATAVIEW_ERROR = i18n.translate('xpack.securitySolution.alertSummary.dataViewError', {
+ defaultMessage: 'Unable to create data view',
+});
export const DATA_VIEW_LOADING_PROMPT_TEST_ID = 'alert-summary-data-view-loading-prompt';
+export const DATA_VIEW_ERROR_TEST_ID = 'alert-summary-data-view-error';
+export const SKELETON_TEST_ID = 'alert-summary-skeleton';
+export const CONTENT_TEST_ID = 'alert-summary-content';
+
+const dataViewSpec: DataViewSpec = { title: '.alerts-security.alerts-default' };
export interface WrapperProps {
/**
@@ -19,12 +37,64 @@ export interface WrapperProps {
}
/**
- * Creates a new dataView with the alert indices while displaying a loading skeleton.
- * Display the alert summary page content if the dataView is correctly created.
- * This page is rendered when there are AI for SOC packages installed.
+ * Creates a new adhoc dataView for the alert summary page. The dataView is created just with the alert indices.
+ * During the creating, we display a loading skeleton, mimicking the future alert summary page content.
+ * Once the dataView is correctly created, we render the content.
+ * If the creation fails, we show an error message.
*/
export const Wrapper = memo(({ packages }: WrapperProps) => {
- return {'Wrapper'};
+ const { data } = useKibana().services;
+ const [dataView, setDataView] = useState(undefined);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ let dv: DataView;
+ const createDataView = async () => {
+ dv = await data.dataViews.create(dataViewSpec);
+ setDataView(dv);
+ setLoading(false);
+ };
+ createDataView();
+
+ // clearing after leaving the page
+ return () => {
+ if (dv?.id) {
+ data.dataViews.clearInstanceCache(dv?.id);
+ }
+ };
+ }, [data.dataViews]);
+
+ return (
+
+
+
+
+
+
+
+
+
+ }
+ loadedContent={
+ <>
+ {!dataView || !dataView.id ? (
+ {DATAVIEW_ERROR}}
+ />
+ ) : (
+ {'wrapper'}
+ )}
+ >
+ }
+ />
+ );
});
Wrapper.displayName = 'Wrapper';
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/pages/alert_summary/alert_summary.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/pages/alert_summary/alert_summary.test.tsx
index 90aafcacfbe46..ba91a9242eeb1 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detections/pages/alert_summary/alert_summary.test.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/detections/pages/alert_summary/alert_summary.test.tsx
@@ -6,15 +6,17 @@
*/
import React from 'react';
-import { render } from '@testing-library/react';
+import { act, render } from '@testing-library/react';
import { AlertSummaryPage, LOADING_INTEGRATIONS_TEST_ID } from './alert_summary';
import { useFetchIntegrations } from '../../hooks/alert_summary/use_fetch_integrations';
import { LANDING_PAGE_PROMPT_TEST_ID } from '../../components/alert_summary/landing_page/landing_page';
import { useAddIntegrationsUrl } from '../../../common/hooks/use_add_integrations_url';
import { DATA_VIEW_LOADING_PROMPT_TEST_ID } from '../../components/alert_summary/wrapper';
+import { useKibana } from '../../../common/lib/kibana';
jest.mock('../../hooks/alert_summary/use_fetch_integrations');
jest.mock('../../../common/hooks/use_add_integrations_url');
+jest.mock('../../../common/lib/kibana');
describe('', () => {
it('should render loading logo', () => {
@@ -40,16 +42,27 @@ describe('', () => {
expect(getByTestId(LANDING_PAGE_PROMPT_TEST_ID)).toBeInTheDocument();
});
- it('should render wrapper if packages are installed', () => {
+ it('should render wrapper if packages are installed', async () => {
+ (useKibana as jest.Mock).mockReturnValue({
+ services: {
+ data: {
+ dataViews: {
+ create: jest.fn(),
+ },
+ },
+ },
+ });
(useFetchIntegrations as jest.Mock).mockReturnValue({
availablePackage: [],
installedPackages: [{ id: 'id' }],
isLoading: false,
});
- const { getByTestId, queryByTestId } = render();
- expect(queryByTestId(LOADING_INTEGRATIONS_TEST_ID)).not.toBeInTheDocument();
- expect(queryByTestId(LANDING_PAGE_PROMPT_TEST_ID)).not.toBeInTheDocument();
- expect(getByTestId(DATA_VIEW_LOADING_PROMPT_TEST_ID)).toBeInTheDocument();
+ await act(async () => {
+ const { getByTestId, queryByTestId } = render();
+ expect(queryByTestId(LOADING_INTEGRATIONS_TEST_ID)).not.toBeInTheDocument();
+ expect(queryByTestId(LANDING_PAGE_PROMPT_TEST_ID)).not.toBeInTheDocument();
+ expect(getByTestId(DATA_VIEW_LOADING_PROMPT_TEST_ID)).toBeInTheDocument();
+ });
});
});