diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_actions.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_actions.tsx
index 0b60555b28f15..6b270f01da2ff 100644
--- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_actions.tsx
+++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_actions.tsx
@@ -7,10 +7,10 @@
import type { VFC } from 'react';
import React, { memo } from 'react';
-import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
+import { EuiButtonIcon, EuiCopy, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
+import { copyFunction } from '../../../shared/utils/copy_to_clipboard';
import { FLYOUT_URL_PARAM } from '../../shared/hooks/url/use_sync_flyout_state_with_url';
-import { CopyToClipboard } from '../../../shared/components/copy_to_clipboard';
import { useGetAlertDetailsFlyoutLink } from '../../../../timelines/components/side_panel/event_details/use_get_alert_details_flyout_link';
import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
import { useRightPanelContext } from '../context';
@@ -31,26 +31,32 @@ export const HeaderActions: VFC = memo(() => {
const showShareAlertButton = isAlert && alertDetailsLink;
+ const modifier = (value: string) => {
+ const query = new URLSearchParams(window.location.search);
+ return `${value}&${FLYOUT_URL_PARAM}=${query.get(FLYOUT_URL_PARAM)}`;
+ };
+
return (
{showShareAlertButton && (
- {
- const query = new URLSearchParams(window.location.search);
- return `${value}&${FLYOUT_URL_PARAM}=${query.get(FLYOUT_URL_PARAM)}`;
- }}
- iconType={'share'}
- color={'text'}
- ariaLabel={i18n.translate(
- 'xpack.securitySolution.flyout.right.header.shareButtonAriaLabel',
- {
- defaultMessage: 'Share Alert',
- }
+
+ {(copy) => (
+ copyFunction(copy, alertDetailsLink, modifier)}
+ onKeyDown={() => copyFunction(copy, alertDetailsLink, modifier)}
+ />
)}
- data-test-subj={SHARE_BUTTON_TEST_ID}
- />
+
)}
diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/tabs/json_tab.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/tabs/json_tab.tsx
index f29a1486819cb..6d329811f7228 100644
--- a/x-pack/plugins/security_solution/public/flyout/document_details/right/tabs/json_tab.tsx
+++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/tabs/json_tab.tsx
@@ -8,10 +8,10 @@
import type { FC } from 'react';
import React, { memo, useEffect, useRef, useState } from 'react';
import { JsonCodeEditor } from '@kbn/unified-doc-viewer-plugin/public';
-import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
+import { EuiButtonEmpty, EuiCopy, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
-import { CopyToClipboard } from '../../../shared/components/copy_to_clipboard';
+import { copyFunction } from '../../../shared/utils/copy_to_clipboard';
import { JSON_TAB_CONTENT_TEST_ID, JSON_TAB_COPY_TO_CLIPBOARD_BUTTON_TEST_ID } from './test_ids';
import { useRightPanelContext } from '../context';
@@ -48,31 +48,35 @@ export const JsonTab: FC = memo(() => {
return (
-
- }
- iconType={'copyClipboard'}
- size={'xs'}
- ariaLabel={i18n.translate(
- 'xpack.securitySolution.flyout.right.jsonTab.copyToClipboardButtonAriaLabel',
- {
- defaultMessage: 'Copy to clipboard',
- }
+
+ {(copy) => (
+ copyFunction(copy, jsonValue)}
+ onKeyDown={() => copyFunction(copy, jsonValue)}
+ >
+
+
)}
- data-test-subj={JSON_TAB_COPY_TO_CLIPBOARD_BUTTON_TEST_ID}
- />
+
diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/copy_to_clipboard.stories.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/copy_to_clipboard.stories.tsx
deleted file mode 100644
index 16519305d2a00..0000000000000
--- a/x-pack/plugins/security_solution/public/flyout/shared/components/copy_to_clipboard.stories.tsx
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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 type { Story } from '@storybook/react';
-import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
-import { CopyToClipboard } from './copy_to_clipboard';
-
-export default {
- component: CopyToClipboard,
- title: 'Flyout/CopyToClipboard',
-};
-
-const json = JSON.stringify({
- foo: 'bar',
-});
-
-export const Default: Story = () => {
- return (
- {'Copy'}
}
- iconType={'copyClipboard'}
- ariaLabel={'Copy'}
- />
- );
-};
-
-export const WithModifier: Story = () => {
- return (
- {
- window.alert('modifier');
- return value;
- }}
- text={{'Copy'}
}
- iconType={'copyClipboard'}
- ariaLabel={'Copy'}
- />
- );
-};
-
-export const MultipleSizes: Story = () => {
- return (
-
-
- {'xs size'}}
- iconType={'copyClipboard'}
- size={'xs'}
- ariaLabel={'Copy'}
- />
-
-
- {'s size'}}
- iconType={'copyClipboard'}
- size={'s'}
- ariaLabel={'Copy'}
- />
-
-
- {'m size'}}
- iconType={'copyClipboard'}
- size={'m'}
- ariaLabel={'Copy'}
- />
-
-
- );
-};
-
-export const ButtonOnly: Story = () => {
- return (
- {
- window.alert('modifier');
- return value;
- }}
- iconType={'copyClipboard'}
- ariaLabel={'Copy'}
- />
- );
-};
-
-export const CustomColor: Story = () => {
- return (
- {
- window.alert('modifier');
- return value;
- }}
- iconType={'copyClipboard'}
- ariaLabel={'Copy'}
- text={{'showing custom color'}
}
- color={'accent'}
- />
- );
-};
-
-export const CustomIcon: Story = () => {
- return (
- {
- window.alert('modifier');
- return value;
- }}
- iconType={'share'}
- ariaLabel={'Share'}
- text={{'custom icon'}
}
- />
- );
-};
diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/copy_to_clipboard.test.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/copy_to_clipboard.test.tsx
deleted file mode 100644
index 1f9c5976f18a9..0000000000000
--- a/x-pack/plugins/security_solution/public/flyout/shared/components/copy_to_clipboard.test.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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 { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
-import { render } from '@testing-library/react';
-import React from 'react';
-import type { CopyToClipboardProps } from './copy_to_clipboard';
-import { CopyToClipboard } from './copy_to_clipboard';
-
-jest.mock('@elastic/eui', () => ({
- ...jest.requireActual('@elastic/eui'),
- copyToClipboard: jest.fn(),
- EuiCopy: jest.fn(({ children: functionAsChild }) => functionAsChild(jest.fn())),
-}));
-
-const renderShareButton = (props: CopyToClipboardProps) =>
- render(
-
-
-
- );
-
-describe('ShareButton', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
- it('should render the copy to clipboard button', () => {
- const text = 'text';
-
- const props = {
- rawValue: 'rawValue',
- text: {text},
- iconType: 'iconType',
- ariaLabel: 'ariaLabel',
- 'data-test-subj': 'data-test-subj',
- };
- const { getByTestId, getByText } = renderShareButton(props);
-
- const button = getByTestId('data-test-subj');
-
- expect(button).toBeInTheDocument();
- expect(button).toHaveAttribute('aria-label', props.ariaLabel);
- expect(button).toHaveAttribute('type', 'button');
-
- expect(getByText(text)).toBeInTheDocument();
- });
-
- it('should use modifier if provided', () => {
- const modifiedFc = jest.fn();
-
- const props = {
- rawValue: 'rawValue',
- modifier: modifiedFc,
- text: {'text'},
- iconType: 'iconType',
- ariaLabel: 'ariaLabel',
- 'data-test-subj': 'data-test-subj',
- };
- const { getByTestId } = renderShareButton(props);
-
- const button = getByTestId('data-test-subj');
-
- button.click();
-
- expect(modifiedFc).toHaveBeenCalledWith(props.rawValue);
- });
-});
diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/copy_to_clipboard.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/copy_to_clipboard.tsx
deleted file mode 100644
index 0727349543d8e..0000000000000
--- a/x-pack/plugins/security_solution/public/flyout/shared/components/copy_to_clipboard.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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 type { EuiButtonEmptyProps } from '@elastic/eui';
-import { copyToClipboard, EuiButtonEmpty, EuiCopy } from '@elastic/eui';
-import type { FC, ReactElement } from 'react';
-import React from 'react';
-
-export interface CopyToClipboardProps {
- /**
- * Value to save to the clipboard
- */
- rawValue: string;
- /**
- * Function to modify the raw value before saving to the clipboard
- */
- modifier?: (rawValue: string) => string;
- /**
- * Button main text (next to icon)
- */
- text?: ReactElement;
- /**
- * Icon name (value coming from EUI)
- */
- iconType: EuiButtonEmptyProps['iconType'];
- /**
- * Button size (values coming from EUI)
- */
- size?: EuiButtonEmptyProps['size'];
- /**
- * Optional button color
- */
- color?: EuiButtonEmptyProps['color'];
- /**
- * Aria label value for the button
- */
- ariaLabel: string;
- /**
- Data test subject string for testing
- */
- ['data-test-subj']?: string;
-}
-
-/**
- * Copy to clipboard component
- */
-export const CopyToClipboard: FC = ({
- rawValue,
- modifier,
- text,
- iconType,
- size = 'm',
- color = 'primary',
- ariaLabel,
- 'data-test-subj': dataTestSubj,
-}) => {
- return (
-
- {(copy) => (
- {
- copy();
-
- if (modifier) {
- const modifiedCopyValue = modifier(rawValue);
- copyToClipboard(modifiedCopyValue);
- } else {
- copyToClipboard(rawValue);
- }
- }}
- iconType={iconType}
- size={size}
- color={color}
- aria-label={ariaLabel}
- data-test-subj={dataTestSubj}
- >
- {text}
-
- )}
-
- );
-};
-
-CopyToClipboard.displayName = 'CopyToClipboard';
diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.tsx
index 3629a711b92d0..47c88da58f693 100644
--- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.tsx
+++ b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.tsx
@@ -105,7 +105,7 @@ export const FlyoutNavigation: FC = memo(
responsive={false}
css={css`
padding-left: ${euiTheme.size.s};
- padding-right: ${euiTheme.size.l};
+ padding-right: ${euiTheme.size.xl};
height: ${euiTheme.size.xxl};
`}
>
diff --git a/x-pack/plugins/security_solution/public/flyout/shared/utils/copy_to_clipboard.test.tsx b/x-pack/plugins/security_solution/public/flyout/shared/utils/copy_to_clipboard.test.tsx
new file mode 100644
index 0000000000000..07816046aa4e1
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/flyout/shared/utils/copy_to_clipboard.test.tsx
@@ -0,0 +1,39 @@
+/*
+ * 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 { copyFunction } from './copy_to_clipboard';
+
+jest.mock('@elastic/eui', () => ({
+ ...jest.requireActual('@elastic/eui'),
+ copyToClipboard: jest.fn(),
+ EuiCopy: jest.fn(({ children: functionAsChild }) => functionAsChild(jest.fn())),
+}));
+
+describe('copyFunction', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ const rawValue = 'rawValue';
+
+ it('should call copy function', () => {
+ const euiCopy = jest.fn();
+
+ copyFunction(euiCopy, rawValue);
+
+ expect(euiCopy).toHaveBeenCalled();
+ });
+
+ it('should call modifier function if passed', () => {
+ const euiCopy = jest.fn();
+ const modifiedFc = jest.fn();
+
+ copyFunction(euiCopy, rawValue, modifiedFc);
+
+ expect(modifiedFc).toHaveBeenCalledWith(rawValue);
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/flyout/shared/utils/copy_to_clipboard.tsx b/x-pack/plugins/security_solution/public/flyout/shared/utils/copy_to_clipboard.tsx
new file mode 100644
index 0000000000000..efc3523edac34
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/flyout/shared/utils/copy_to_clipboard.tsx
@@ -0,0 +1,31 @@
+/*
+ * 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 { copyToClipboard } from '@elastic/eui';
+
+/**
+ * Copy to clipboard wrapper component. It allows adding a copy to clipboard functionality to any element.
+ * It expects the value to be copied with an optional function to modify the value if necessary.
+ *
+ * @param copy the copy method from EuiCopy
+ * @param rawValue the value to save to the clipboard
+ * @param modifier a function to modify the raw value before saving to the clipboard
+ */
+export const copyFunction = (
+ copy: Function,
+ rawValue: string,
+ modifier?: (rawValue: string) => string
+) => {
+ copy();
+
+ if (modifier) {
+ const modifiedCopyValue = modifier(rawValue);
+ copyToClipboard(modifiedCopyValue);
+ } else {
+ copyToClipboard(rawValue);
+ }
+};