Skip to content

Commit

Permalink
[8.x] [Security Solution] Connector selector onboarding (#203742) (#2…
Browse files Browse the repository at this point in the history
…08205)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Security Solution] Connector selector onboarding
(#203742)](#203742)

<!--- Backport version: 9.6.4 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Agustina Nahir
Ruidiaz","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-01-24T12:47:41Z","message":"[Security
Solution] Connector selector onboarding (#203742)\n\n##
Summary\r\n\r\nSummarize your PR. If it involves visual changes include
a screenshot
or\r\ngif.\r\n\r\n\r\nhttps://github.com/user-attachments/assets/6d7527d1-dc8d-4f3a-9b03-cfd0022701d2\r\n\r\n\r\n\r\n###
Checklist\r\n\r\nCheck the PR satisfies following conditions.
\r\n\r\nReviewers should verify this PR satisfies this list as
well.\r\n\r\n- [ ] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine
<[email protected]>\r\nCo-authored-by:
kibanamachine
<[email protected]>","sha":"86666bf790c87ee8bde353d53dcf5413e80e50e5","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Threat
Hunting:Explore","ci:cloud-deploy","backport:version","v8.18.0"],"title":"[Security
Solution] Connector selector
onboarding","number":203742,"url":"https://github.com/elastic/kibana/pull/203742","mergeCommit":{"message":"[Security
Solution] Connector selector onboarding (#203742)\n\n##
Summary\r\n\r\nSummarize your PR. If it involves visual changes include
a screenshot
or\r\ngif.\r\n\r\n\r\nhttps://github.com/user-attachments/assets/6d7527d1-dc8d-4f3a-9b03-cfd0022701d2\r\n\r\n\r\n\r\n###
Checklist\r\n\r\nCheck the PR satisfies following conditions.
\r\n\r\nReviewers should verify this PR satisfies this list as
well.\r\n\r\n- [ ] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine
<[email protected]>\r\nCo-authored-by:
kibanamachine
<[email protected]>","sha":"86666bf790c87ee8bde353d53dcf5413e80e50e5"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/203742","number":203742,"mergeCommit":{"message":"[Security
Solution] Connector selector onboarding (#203742)\n\n##
Summary\r\n\r\nSummarize your PR. If it involves visual changes include
a screenshot
or\r\ngif.\r\n\r\n\r\nhttps://github.com/user-attachments/assets/6d7527d1-dc8d-4f3a-9b03-cfd0022701d2\r\n\r\n\r\n\r\n###
Checklist\r\n\r\nCheck the PR satisfies following conditions.
\r\n\r\nReviewers should verify this PR satisfies this list as
well.\r\n\r\n- [ ] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine
<[email protected]>\r\nCo-authored-by:
kibanamachine
<[email protected]>","sha":"86666bf790c87ee8bde353d53dcf5413e80e50e5"}},{"branch":"8.x","label":"v8.18.0","branchLabelMappingKey":"^v8.18.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

---------

Co-authored-by: kibanamachine <[email protected]>
  • Loading branch information
agusruidiazgd and kibanamachine authored Jan 24, 2025
1 parent 8d19a66 commit db7b5e2
Show file tree
Hide file tree
Showing 26 changed files with 740 additions and 304 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,7 @@ x-pack/platform/packages/shared/security/plugin_types_common @elastic/kibana-sec
x-pack/platform/packages/shared/security/plugin_types_public @elastic/kibana-security
x-pack/platform/packages/shared/security/plugin_types_server @elastic/kibana-security
x-pack/platform/packages/private/security/role_management_model @elastic/kibana-security
x-pack/solutions/security/packages/connectors @elastic/security-threat-hunting-explore
x-pack/solutions/security/packages/distribution_bar @elastic/kibana-cloud-security-posture
x-pack/solutions/security/plugins/security_solution_ess @elastic/security-solution
x-pack/solutions/security/packages/features @elastic/security-threat-hunting-explore
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,7 @@
"@kbn/security-plugin-types-public": "link:x-pack/platform/packages/shared/security/plugin_types_public",
"@kbn/security-plugin-types-server": "link:x-pack/platform/packages/shared/security/plugin_types_server",
"@kbn/security-role-management-model": "link:x-pack/platform/packages/private/security/role_management_model",
"@kbn/security-solution-connectors": "link:x-pack/solutions/security/packages/connectors",
"@kbn/security-solution-distribution-bar": "link:x-pack/solutions/security/packages/distribution_bar",
"@kbn/security-solution-ess": "link:x-pack/solutions/security/plugins/security_solution_ess",
"@kbn/security-solution-features": "link:x-pack/solutions/security/packages/features",
Expand Down
2 changes: 2 additions & 0 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -1632,6 +1632,8 @@
"@kbn/security-plugin-types-server/*": ["x-pack/platform/packages/shared/security/plugin_types_server/*"],
"@kbn/security-role-management-model": ["x-pack/platform/packages/private/security/role_management_model"],
"@kbn/security-role-management-model/*": ["x-pack/platform/packages/private/security/role_management_model/*"],
"@kbn/security-solution-connectors": ["x-pack/solutions/security/packages/connectors"],
"@kbn/security-solution-connectors/*": ["x-pack/solutions/security/packages/connectors/*"],
"@kbn/security-solution-distribution-bar": ["x-pack/solutions/security/packages/distribution_bar"],
"@kbn/security-solution-distribution-bar/*": ["x-pack/solutions/security/packages/distribution_bar/*"],
"@kbn/security-solution-ess": ["x-pack/solutions/security/plugins/security_solution_ess"],
Expand Down
9 changes: 9 additions & 0 deletions x-pack/solutions/security/packages/connectors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 { ConnectorSelector } from './src/connector_selector';
export type { ConnectorSelectorProps } from './src/connector_selector';
12 changes: 12 additions & 0 deletions x-pack/solutions/security/packages/connectors/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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.
*/

module.exports = {
preset: '@kbn/test',
roots: ['<rootDir>/x-pack/solutions/security/packages/connectors'],
rootDir: '../../../../..',
};
9 changes: 9 additions & 0 deletions x-pack/solutions/security/packages/connectors/kibana.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"type": "shared-browser",
"id": "@kbn/security-solution-connectors",
"owner": [
"@elastic/security-threat-hunting-explore"
],
"group": "security",
"visibility": "private"
}
7 changes: 7 additions & 0 deletions x-pack/solutions/security/packages/connectors/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "@kbn/security-solution-connectors",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0",
"sideEffects": false
}
Original file line number Diff line number Diff line change
@@ -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 { useEuiTheme } from '@elastic/eui';
import { css } from '@emotion/react';

export const useConnectorSelectorStyles = () => {
const { euiTheme } = useEuiTheme();

return {
placeholder: css`
color: ${euiTheme.colors.primary};
margin-right: ${euiTheme.size.xs};
`,
optionDisplay: css`
margin-right: 8px;
overflow: hidden;
text-overflow: ellipsis;
`,
offset: css`
width: 24px;
`,
inputContainer: css`
.euiSuperSelectControl {
border: none;
box-shadow: none;
background: none;
padding-left: 0;
}
.euiFormControlLayoutIcons {
right: 14px;
top: 2px;
}
`,
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* 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 {
EuiButtonEmpty,
EuiFlexGroup,
EuiFlexItem,
EuiSuperSelect,
EuiText,
useEuiTheme,
} from '@elastic/eui';
import React, { useCallback, useMemo } from 'react';
import { some } from 'lodash';
import * as i18n from './translations';
import { useConnectorSelectorStyles } from './connector_selector.styles';
import { ADD_NEW_CONNECTOR } from './constants';

export interface ConnectorDetails {
id: string;
name: string;
description: string;
}

export interface ConnectorSelectorProps {
connectors: ConnectorDetails[];
onChange: (connectorId: string) => void;
selectedId?: string;
onNewConnectorClicked?: () => void;
isDisabled?: boolean;
}

export const ConnectorSelector = React.memo<ConnectorSelectorProps>(
({ connectors, onChange, selectedId, onNewConnectorClicked, isDisabled }) => {
const styles = useConnectorSelectorStyles();
const { euiTheme } = useEuiTheme();

const addNewConnectorOption = useMemo(() => {
return {
value: ADD_NEW_CONNECTOR,
inputDisplay: i18n.ADD_NEW_CONNECTOR,
dropdownDisplay: (
<EuiFlexGroup gutterSize="none" key={ADD_NEW_CONNECTOR}>
<EuiFlexItem grow={true}>
<EuiButtonEmpty
data-test-subj="addNewConnectorButton"
href="#"
isDisabled={isDisabled}
iconType="plus"
size="xs"
>
{i18n.ADD_NEW_CONNECTOR}
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
{/* Right offset to compensate for 'selected' icon of EuiSuperSelect since native footers aren't supported*/}
<div css={styles.offset} />
</EuiFlexItem>
</EuiFlexGroup>
),
};
}, [isDisabled, styles.offset]);

const connectorExists = useMemo(
() => some(connectors, ['id', selectedId]),
[connectors, selectedId]
);

const mappedConnectorOptions = connectors.map((connector) => ({
value: connector.id,
'data-test-subj': connector.id,
inputDisplay: (
<EuiText css={styles.optionDisplay} size="s" color={euiTheme.colors.primary}>
{connector.name}
</EuiText>
),
dropdownDisplay: (
<React.Fragment key={connector.id}>
<EuiFlexGroup justifyContent="spaceBetween" gutterSize="none" alignItems="center">
<EuiFlexItem grow={false} data-test-subj={`connector-${connector.name}`}>
<strong>{connector.name}</strong>
<EuiText size="xs" color="subdued">
<p>{connector.description}</p>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</React.Fragment>
),
}));

const allConnectorOptions = useMemo(
() =>
onNewConnectorClicked
? [...mappedConnectorOptions, addNewConnectorOption]
: [...mappedConnectorOptions],
[onNewConnectorClicked, mappedConnectorOptions, addNewConnectorOption]
);

const onChangeConnector = useCallback(
(connectorId: string) => {
if (connectorId === ADD_NEW_CONNECTOR) {
onNewConnectorClicked?.();
return;
}
onChange(connectorId);
},
[onChange, onNewConnectorClicked]
);

return (
<div css={styles.inputContainer}>
{!connectorExists && !connectors.length ? (
<EuiButtonEmpty
data-test-subj="addNewConnectorButton"
iconType="plusInCircle"
isDisabled={isDisabled}
size="xs"
onClick={() => onNewConnectorClicked?.()}
>
{i18n.ADD_CONNECTOR}
</EuiButtonEmpty>
) : (
<EuiSuperSelect
aria-label={i18n.CONNECTOR_SELECTOR_TITLE}
css={styles.placeholder}
compressed={true}
data-test-subj="connector-selector"
disabled={isDisabled}
hasDividers={true}
onChange={onChangeConnector}
options={allConnectorOptions}
valueOfSelected={selectedId}
placeholder={i18n.CONNECTOR_SELECTOR_PLACEHOLDER}
popoverProps={{ panelMinWidth: 400, anchorPosition: 'downRight' }}
/>
)}
</div>
);
}
);

ConnectorSelector.displayName = 'ConnectorSelector';
Original file line number Diff line number Diff line change
@@ -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 ADD_NEW_CONNECTOR = 'ADD_NEW_CONNECTOR';
36 changes: 36 additions & 0 deletions x-pack/solutions/security/packages/connectors/src/translations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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 { i18n } from '@kbn/i18n';

export const CONNECTOR_SELECTOR_TITLE = i18n.translate(
'securitySolutionPackages.connectors.connectorSelector.ariaLabel',
{
defaultMessage: 'Connector Selector',
}
);

export const ADD_NEW_CONNECTOR = i18n.translate(
'securitySolutionPackages.connectors.connectorSelector.newConnectorOptions',
{
defaultMessage: 'Add new Connector...',
}
);

export const ADD_CONNECTOR = i18n.translate(
'securitySolutionPackages.connectors.connectorSelector.addConnectorButtonLabel',
{
defaultMessage: 'Add connector',
}
);

export const CONNECTOR_SELECTOR_PLACEHOLDER = i18n.translate(
'securitySolutionPackages.connectors.connectorSelectorInline.connectorPlaceholder',
{
defaultMessage: 'Select a connector',
}
);
19 changes: 19 additions & 0 deletions x-pack/solutions/security/packages/connectors/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"extends": "../../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node",
"react",
"@emotion/react/types/css-prop",
"@testing-library/jest-dom",
"@testing-library/react",
]
},
"include": ["**/*.ts", "**/*.tsx"],
"kbn_references": [
"@kbn/i18n",
],
"exclude": ["target/**/*"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const LocalStorageKey = {
selectedIntegrationTabId: 'securitySolution.onboarding.selectedIntegrationTabId',
selectedCardItemId: 'securitySolution.onboarding.selectedCardItem',
integrationSearchTerm: 'securitySolution.onboarding.integrationSearchTerm',
assistantConnectorId: 'securitySolution.onboarding.assistantCard.connectorId',
} as const;

/**
Expand Down Expand Up @@ -80,3 +81,9 @@ export const useStoredIntegrationSearchTerm = (spaceId: string) =>
`${LocalStorageKey.integrationSearchTerm}.${spaceId}`,
null
);

/**
* Stores the integration search term per space
*/
export const useStoredAssistantConnectorId = (spaceId: string) =>
useDefinedLocalStorage<string | null>(`${LocalStorageKey.assistantConnectorId}.${spaceId}`, null);
Loading

0 comments on commit db7b5e2

Please sign in to comment.