[SecuritySolution] Create integration link added to Security onboarding page (#187201)

## Summary

Link panel to go to create integrations added. It is a compressed
version of the link card displayed on the integrations page. The
integration creation feature is not enabled by default, to enable the
feature:
```
xpack.integration_assistant.enabled: true
```


![link](2532819e-da6e-4d2f-ab07-45042d6a069f)

When the integrationAssistant plugin is not enabled (default) the link
does not appear.


![no_link](82cc67b1-ce16-4fd8-ad59-f8a4d4cd31fb)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Sergi Massaneda 2024-07-01 13:58:27 +02:00 committed by GitHub
parent 1eb7a5ee0b
commit fc02b21daf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 85 additions and 51 deletions

View file

@ -81,7 +81,7 @@ export const DefaultLayout: React.FC<Props> = memo(
rightColumn={ rightColumn={
CreateIntegrationCardButton ? ( CreateIntegrationCardButton ? (
<EuiFlexItem grow={false}> <EuiFlexItem grow={false}>
<CreateIntegrationCardButton href={getHref('integration_create')} /> <CreateIntegrationCardButton />
</EuiFlexItem> </EuiFlexItem>
) : undefined ) : undefined
} }

View file

@ -5,7 +5,7 @@
* 2.0. * 2.0.
*/ */
import React from 'react'; import React, { useCallback, useMemo } from 'react';
import { import {
EuiLink, EuiLink,
EuiPanel, EuiPanel,
@ -15,41 +15,53 @@ import {
EuiIcon, EuiIcon,
EuiText, EuiText,
EuiTitle, EuiTitle,
useEuiTheme, useEuiPaddingCSS,
} from '@elastic/eui'; } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react'; import { FormattedMessage } from '@kbn/i18n-react';
import { css } from '@emotion/react'; import { css } from '@emotion/react';
import integrationsImage from '../../common/images/integrations_light.svg'; import integrationsImage from '../../common/images/integrations_light.svg';
import { useKibana } from '../../common/hooks/use_kibana';
const useStyles = () => { const useStyles = (compressed: boolean) => {
const { euiTheme } = useEuiTheme(); const paddings = useEuiPaddingCSS();
return { return {
image: css` image: css`
width: 160px; width: ${compressed ? '140px' : '160px'};
height: 155px; height: ${compressed ? '90px' : '155px'};
object-fit: cover; object-fit: cover;
object-position: left center; object-position: left center;
`, `,
container: css` container: css`
height: 135px; height: ${compressed ? '80px' : '135px'};
`, `,
textContainer: css` textContainer: css`
height: 100%; height: 100%;
padding: ${euiTheme.size.l} 0 ${euiTheme.size.l} ${euiTheme.size.l}; ${compressed ? `${paddings.m.styles}` : `${paddings.l.styles} padding-right: 0;`}
`, `,
}; };
}; };
export interface CreateIntegrationCardButtonProps { export interface CreateIntegrationCardButtonProps {
href: string; compressed?: boolean;
} }
export const CreateIntegrationCardButton = React.memo<CreateIntegrationCardButtonProps>( export const CreateIntegrationCardButton = React.memo<CreateIntegrationCardButtonProps>(
({ href }) => { ({ compressed = false }) => {
const styles = useStyles(); const { getUrlForApp, navigateToUrl } = useKibana().services.application;
const styles = useStyles(compressed);
const href = useMemo(() => getUrlForApp('integrations', { path: '/create' }), [getUrlForApp]);
const navigate = useCallback(
(ev) => {
ev.preventDefault();
navigateToUrl(href);
},
[href, navigateToUrl]
);
return ( return (
<EuiPanel hasShadow={false} hasBorder paddingSize="none"> <EuiPanel hasShadow={false} hasBorder paddingSize="none">
<EuiFlexGroup <EuiFlexGroup
justifyContent="flexEnd" justifyContent="spaceBetween"
gutterSize="none" gutterSize="none"
css={styles.container} css={styles.container}
responsive={false} responsive={false}
@ -70,18 +82,26 @@ export const CreateIntegrationCardButton = React.memo<CreateIntegrationCardButto
/> />
</h2> </h2>
</EuiTitle> </EuiTitle>
<EuiText size="s"> {!compressed && (
<FormattedMessage <EuiText size="s">
id="xpack.integrationAssistant.createIntegrationDescription" <FormattedMessage
defaultMessage="Create a custom one to fit your requirements" id="xpack.integrationAssistant.createIntegrationDescription"
/> defaultMessage="Create a custom one to fit your requirements"
</EuiText> />
</EuiText>
)}
</EuiFlexItem> </EuiFlexItem>
<EuiFlexItem grow={false}> <EuiFlexItem grow={false}>
<EuiLink color="primary" href={href}> {/* eslint-disable-next-line @elastic/eui/href-or-on-click */}
<EuiFlexGroup justifyContent="center" gutterSize="s" responsive={false}> <EuiLink color="primary" href={href} onClick={navigate}>
<EuiFlexGroup
justifyContent="center"
alignItems="center"
gutterSize={compressed ? 'xs' : 's'}
responsive={false}
>
<EuiFlexItem grow={false}> <EuiFlexItem grow={false}>
<EuiIcon type="plusInCircle" /> <EuiIcon type="plusInCircle" size={compressed ? 's' : 'm'} />
</EuiFlexItem> </EuiFlexItem>
<EuiFlexItem> <EuiFlexItem>
<FormattedMessage <FormattedMessage

View file

@ -70,7 +70,8 @@
"dataViewFieldEditor", "dataViewFieldEditor",
"osquery", "osquery",
"savedObjectsTaggingOss", "savedObjectsTaggingOss",
"guidedOnboarding" "guidedOnboarding",
"integrationAssistant"
], ],
"requiredBundles": [ "requiredBundles": [
"esUiShared", "esUiShared",

View file

@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n';
import { LinkButton } from '@kbn/security-solution-navigation/links'; import { LinkButton } from '@kbn/security-solution-navigation/links';
import type { IconType } from '@elastic/eui'; import type { IconType } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiPanel, EuiText, EuiTitle } from '@elastic/eui'; import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiPanel, EuiText, EuiTitle } from '@elastic/eui';
import { useKibana } from '../../../../lib/kibana/kibana_react';
import { AddIntegrationsSteps } from '../types'; import { AddIntegrationsSteps } from '../types';
import { useStepContext } from '../context/step_context'; import { useStepContext } from '../context/step_context';
import { IntegrationsPageName } from './types'; import { IntegrationsPageName } from './types';
@ -153,32 +154,41 @@ const AddIntegrationPanel: React.FC<{
}); });
AddIntegrationPanel.displayName = 'AddIntegrationPanel'; AddIntegrationPanel.displayName = 'AddIntegrationPanel';
export const AddIntegrationButtons: React.FC = React.memo(() => ( export const AddIntegrationButtons: React.FC = React.memo(() => {
<EuiFlexGroup direction="column" className="step-paragraph" gutterSize="m"> const { integrationAssistant } = useKibana().services;
<EuiFlexItem grow={false}> const CreateIntegrationCardButton = integrationAssistant?.CreateIntegrationCardButton;
<AddIntegrationPanel return (
title={ADD_CLOUD_INTEGRATIONS_TITLE} <EuiFlexGroup direction="column" className="step-paragraph" gutterSize="m">
description={ADD_CLOUD_INTEGRATIONS_DESCRIPTION} <EuiFlexItem grow={false}>
icon={CloudIntegrationsIcon} <AddIntegrationPanel
buttonId={IntegrationsPageName.integrationsSecurityCloud} title={ADD_CLOUD_INTEGRATIONS_TITLE}
/> description={ADD_CLOUD_INTEGRATIONS_DESCRIPTION}
</EuiFlexItem> icon={CloudIntegrationsIcon}
<EuiFlexItem grow={false}> buttonId={IntegrationsPageName.integrationsSecurityCloud}
<AddIntegrationPanel />
title={ADD_EDR_XDR_INTEGRATIONS_TITLE} </EuiFlexItem>
description={ADD_EDR_XDR_INTEGRATIONS_DESCRIPTION} <EuiFlexItem grow={false}>
icon={EdrXdrIntegrationsIcon} <AddIntegrationPanel
buttonId={IntegrationsPageName.integrationsSecurityEdrXrd} title={ADD_EDR_XDR_INTEGRATIONS_TITLE}
/> description={ADD_EDR_XDR_INTEGRATIONS_DESCRIPTION}
</EuiFlexItem> icon={EdrXdrIntegrationsIcon}
<EuiFlexItem grow={false}> buttonId={IntegrationsPageName.integrationsSecurityEdrXrd}
<AddIntegrationPanel />
title={ADD_ALL_INTEGRATIONS_TITLE} </EuiFlexItem>
description={ADD_ALL_INTEGRATIONS_DESCRIPTION} <EuiFlexItem grow={false}>
icon="logoSecurity" <AddIntegrationPanel
buttonId={IntegrationsPageName.integrationsSecurity} title={ADD_ALL_INTEGRATIONS_TITLE}
/> description={ADD_ALL_INTEGRATIONS_DESCRIPTION}
</EuiFlexItem> icon="logoSecurity"
</EuiFlexGroup> buttonId={IntegrationsPageName.integrationsSecurity}
)); />
</EuiFlexItem>
{CreateIntegrationCardButton && (
<EuiFlexItem grow={false}>
<CreateIntegrationCardButton compressed />
</EuiFlexItem>
)}
</EuiFlexGroup>
);
});
AddIntegrationButtons.displayName = 'AddIntegrationButtons'; AddIntegrationButtons.displayName = 'AddIntegrationButtons';

View file

@ -60,6 +60,7 @@ import type { ChartsPluginStart } from '@kbn/charts-plugin/public';
import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public';
import type { PluginStartContract } from '@kbn/alerting-plugin/public/plugin'; import type { PluginStartContract } from '@kbn/alerting-plugin/public/plugin';
import type { MapsStartApi } from '@kbn/maps-plugin/public'; import type { MapsStartApi } from '@kbn/maps-plugin/public';
import type { IntegrationAssistantPluginStart } from '@kbn/integration-assistant-plugin/public';
import type { ResolverPluginSetup } from './resolver/types'; import type { ResolverPluginSetup } from './resolver/types';
import type { Inspect } from '../common/search_strategy'; import type { Inspect } from '../common/search_strategy';
import type { Detections } from './detections'; import type { Detections } from './detections';
@ -152,6 +153,7 @@ export interface StartPlugins {
savedSearch: SavedSearchPublicPluginStart; savedSearch: SavedSearchPublicPluginStart;
alerting: PluginStartContract; alerting: PluginStartContract;
core: CoreStart; core: CoreStart;
integrationAssistant?: IntegrationAssistantPluginStart;
} }
export interface StartPluginsDependencies extends StartPlugins { export interface StartPluginsDependencies extends StartPlugins {

View file

@ -209,5 +209,6 @@
"@kbn/core-analytics-browser", "@kbn/core-analytics-browser",
"@kbn/core-i18n-browser", "@kbn/core-i18n-browser",
"@kbn/core-theme-browser", "@kbn/core-theme-browser",
"@kbn/integration-assistant-plugin",
] ]
} }