diff --git a/x-pack/plugins/security_solution/public/common/components/empty_prompt/__mocks__/index.tsx b/x-pack/plugins/security_solution/public/common/components/empty_prompt/__mocks__/index.tsx new file mode 100644 index 0000000000000..ae193bda9e3fc --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/empty_prompt/__mocks__/index.tsx @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +export const EmptyPrompt = () =>
; diff --git a/x-pack/plugins/security_solution/public/common/components/empty_prompt/constants.ts b/x-pack/plugins/security_solution/public/common/components/empty_prompt/constants.ts new file mode 100644 index 0000000000000..0cf6b35ceab99 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/empty_prompt/constants.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const VIDEO_SOURCE = '//play.vidyard.com/K6kKDBbP9SpXife9s2tHNP.html?'; diff --git a/x-pack/plugins/security_solution/public/common/components/empty_prompt/empty_prompt.test.tsx b/x-pack/plugins/security_solution/public/common/components/empty_prompt/empty_prompt.test.tsx new file mode 100644 index 0000000000000..c64d61d2bd226 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/empty_prompt/empty_prompt.test.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { fireEvent, render } from '@testing-library/react'; +import { EmptyPromptComponent } from './empty_prompt'; +import { SecurityPageName } from '../../../../common'; +import { useNavigateTo } from '../../lib/kibana'; +import { AddIntegrationsSteps } from '../landing_page/onboarding/types'; + +const mockNavigateTo = jest.fn(); +const mockUseNavigateTo = useNavigateTo as jest.Mock; + +jest.mock('../../lib/kibana', () => ({ + useNavigateTo: jest.fn(), +})); + +describe('EmptyPromptComponent component', () => { + beforeEach(() => { + jest.clearAllMocks(); + mockUseNavigateTo.mockImplementation(() => ({ navigateTo: mockNavigateTo })); + }); + + it('has add data links', () => { + const { getAllByText } = render(); + expect(getAllByText('Add security integrations')).toHaveLength(2); + }); + + describe.each(['header', 'footer'])('URLs at the %s', (place) => { + it('points to the default Add data URL', () => { + const { getByTestId } = render(); + const link = getByTestId(`add-integrations-${place}`); + fireEvent.click(link); + expect(mockNavigateTo).toBeCalledWith({ + deepLinkId: SecurityPageName.landing, + path: `#${AddIntegrationsSteps.connectToDataSources}`, + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/empty_prompt/empty_prompt.tsx b/x-pack/plugins/security_solution/public/common/components/empty_prompt/empty_prompt.tsx new file mode 100644 index 0000000000000..853b064233c3b --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/empty_prompt/empty_prompt.tsx @@ -0,0 +1,180 @@ +/* + * 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, { memo, useCallback } from 'react'; +import { + EuiButton, + EuiCard, + EuiFlexGroup, + EuiFlexItem, + EuiPageHeader, + useEuiTheme, + type EuiThemeComputed, +} from '@elastic/eui'; +import { css } from '@emotion/react'; +import { SecurityPageName } from '../../../../common'; + +import * as i18n from './translations'; +import endpointSvg from './images/endpoint1.svg'; +import cloudSvg from './images/cloud1.svg'; +import siemSvg from './images/siem1.svg'; +import { useNavigateTo } from '../../lib/kibana'; +import { VIDEO_SOURCE } from './constants'; +import { AddIntegrationsSteps } from '../landing_page/onboarding/types'; + +const imgUrls = { + cloud: cloudSvg, + siem: siemSvg, + endpoint: endpointSvg, +}; + +const headerCardStyles = css` + span.euiTitle { + font-size: 36px; + line-height: 100%; + } +`; + +const pageHeaderStyles = css` + h1 { + font-size: 18px; + } +`; + +const getFlexItemStyles = (euiTheme: EuiThemeComputed) => css` + background: ${euiTheme.colors.lightestShade}; + padding: 20px; +`; + +const cardStyles = css` + img { + margin-top: 20px; + max-width: 400px; + } +`; + +const footerStyles = css` + span.euiTitle { + font-size: 36px; + line-height: 100%; + } + max-width: 600px; + display: block; + margin: 20px auto 0; +`; + +export const EmptyPromptComponent: React.FC = memo(() => { + const { euiTheme } = useEuiTheme(); + + const { navigateTo } = useNavigateTo(); + + const navigateToAddIntegrations = useCallback(() => { + navigateTo({ + deepLinkId: SecurityPageName.landing, + path: `#${AddIntegrationsSteps.connectToDataSources}`, + }); + }, [navigateTo]); + + const onClick = useCallback(() => { + navigateToAddIntegrations(); + }, [navigateToAddIntegrations]); + + return ( + + + + + + + {i18n.SIEM_CTA} + + } + css={headerCardStyles} + /> + + +