[Security Solution] Expandable flyout - add back chat button to alerts flyout (#171262)

## Summary

This PR adds back the chat button to the expandable flyout. Updated
design to be icon only


![image](e56b0ffc-9f51-423c-8072-61cb3839d9a3)


### Checklist

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
This commit is contained in:
christineweng 2023-11-15 12:02:02 -06:00 committed by GitHub
parent dcd8687a60
commit 09e23e51c5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 9 deletions

View file

@ -63,6 +63,15 @@ describe('NewChatById', () => {
expect(newChatButton.querySelector('.euiButtonContent__icon')).not.toBeInTheDocument();
});
it('renders button icon when iconOnly is true', async () => {
render(<NewChatById iconOnly />);
const newChatButton = screen.getByTestId('newChatById');
expect(newChatButton.querySelector('[data-euiicon-type="discuss"]')).toBeInTheDocument();
expect(newChatButton.textContent).not.toContain('Chat');
});
it('calls showAssistantOverlay on click', () => {
const conversationId = 'test-conversation-id';
const promptContextId = 'test-prompt-context-id';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { EuiButtonEmpty } from '@elastic/eui';
import { EuiButtonEmpty, EuiButtonIcon, EuiToolTip } from '@elastic/eui';
import React, { useCallback, useMemo } from 'react';
import { useAssistantContext } from '../assistant_context';
@ -20,6 +20,8 @@ export interface Props {
iconType?: string | null;
/** Optionally specify a well known ID, or default to a UUID */
promptContextId?: string;
/** Defaults to false. If true, shows icon button without text */
iconOnly?: boolean;
}
const NewChatByIdComponent: React.FC<Props> = ({
@ -27,6 +29,7 @@ const NewChatByIdComponent: React.FC<Props> = ({
conversationId,
iconType,
promptContextId,
iconOnly = false,
}) => {
const { showAssistantOverlay } = useAssistantContext();
@ -50,12 +53,28 @@ const NewChatByIdComponent: React.FC<Props> = ({
}, [iconType]);
return useMemo(
() => (
<EuiButtonEmpty data-test-subj="newChatById" iconType={icon} onClick={showOverlay}>
{children}
</EuiButtonEmpty>
),
[children, icon, showOverlay]
() =>
iconOnly ? (
<EuiToolTip content={i18n.NEW_CHAT}>
<EuiButtonIcon
data-test-subj="newChatById"
iconType={icon ?? 'discuss'}
onClick={showOverlay}
color={'text'}
aria-label={i18n.NEW_CHAT}
/>
</EuiToolTip>
) : (
<EuiButtonEmpty
data-test-subj="newChatById"
iconType={icon}
onClick={showOverlay}
aria-label={i18n.NEW_CHAT}
>
{children}
</EuiButtonEmpty>
),
[children, icon, showOverlay, iconOnly]
);
};

View file

@ -10,8 +10,9 @@ import { render, fireEvent } from '@testing-library/react';
import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context';
import { copyToClipboard } from '@elastic/eui';
import { RightPanelContext } from '../context';
import { SHARE_BUTTON_TEST_ID } from './test_ids';
import { SHARE_BUTTON_TEST_ID, CHAT_BUTTON_TEST_ID } from './test_ids';
import { HeaderActions } from './header_actions';
import { useAssistant } from '../hooks/use_assistant';
import { mockGetFieldsData } from '../../shared/mocks/mock_get_fields_data';
import { mockDataFormattedForFieldBrowser } from '../../shared/mocks/mock_data_formatted_for_field_browser';
import { TestProvidersComponent } from '../../../../common/mock';
@ -19,6 +20,7 @@ import { useGetAlertDetailsFlyoutLink } from '../../../../timelines/components/s
import { FLYOUT_URL_PARAM } from '../../shared/hooks/url/use_sync_flyout_state_with_url';
jest.mock('../../../../common/lib/kibana');
jest.mock('../hooks/use_assistant');
jest.mock(
'../../../../timelines/components/side_panel/event_details/use_get_alert_details_flyout_link'
);
@ -50,6 +52,7 @@ const renderHeaderActions = (contextValue: RightPanelContext) =>
describe('<HeaderAction />', () => {
beforeEach(() => {
jest.mocked(useGetAlertDetailsFlyoutLink).mockReturnValue(alertUrl);
jest.mocked(useAssistant).mockReturnValue({ showAssistant: true, promptContextId: '' });
});
describe('Share alert url action', () => {
@ -87,5 +90,19 @@ describe('<HeaderAction />', () => {
});
expect(queryByTestId(SHARE_BUTTON_TEST_ID)).not.toBeInTheDocument();
});
it('should render chat button in the title', () => {
const { getByTestId } = renderHeaderActions(mockContextValue);
expect(getByTestId(CHAT_BUTTON_TEST_ID)).toBeInTheDocument();
});
it('should not render chat button in the title if should not be shown', () => {
jest.mocked(useAssistant).mockReturnValue({ showAssistant: false, promptContextId: '' });
const { queryByTestId } = renderHeaderActions(mockContextValue);
expect(queryByTestId(CHAT_BUTTON_TEST_ID)).not.toBeInTheDocument();
});
});
});

View file

@ -9,10 +9,16 @@ import type { VFC } from 'react';
import React, { memo } from 'react';
import { EuiButtonIcon, EuiCopy, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { NewChatById } from '@kbn/elastic-assistant';
import { copyFunction } from '../../../shared/utils/copy_to_clipboard';
import { FLYOUT_URL_PARAM } from '../../shared/hooks/url/use_sync_flyout_state_with_url';
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 { useAssistant } from '../hooks/use_assistant';
import {
ALERT_SUMMARY_CONVERSATION_ID,
EVENT_SUMMARY_CONVERSATION_ID,
} from '../../../../common/components/event_details/translations';
import { useRightPanelContext } from '../context';
import { SHARE_BUTTON_TEST_ID } from './test_ids';
@ -36,8 +42,28 @@ export const HeaderActions: VFC = memo(() => {
return `${value}&${FLYOUT_URL_PARAM}=${query.get(FLYOUT_URL_PARAM)}`;
};
const { showAssistant, promptContextId } = useAssistant({
dataFormattedForFieldBrowser,
isAlert,
});
return (
<EuiFlexGroup direction="row" justifyContent="flexEnd">
<EuiFlexGroup
direction="row"
justifyContent="flexEnd"
alignItems="center"
gutterSize="none"
responsive={false}
>
{showAssistant && (
<EuiFlexItem grow={false}>
<NewChatById
conversationId={isAlert ? ALERT_SUMMARY_CONVERSATION_ID : EVENT_SUMMARY_CONVERSATION_ID}
promptContextId={promptContextId}
iconOnly
/>
</EuiFlexItem>
)}
{showShareAlertButton && (
<EuiFlexItem grow={false}>
<EuiCopy textToCopy={alertDetailsLink}>

View file

@ -17,6 +17,7 @@ export const SEVERITY_VALUE_TEST_ID = 'severity' as const;
export const RISK_SCORE_TITLE_TEST_ID = `${FLYOUT_HEADER_TEST_ID}RiskScoreTitle` as const;
export const RISK_SCORE_VALUE_TEST_ID = `${FLYOUT_HEADER_TEST_ID}RiskScoreValue` as const;
export const SHARE_BUTTON_TEST_ID = `${FLYOUT_HEADER_TEST_ID}ShareButton` as const;
export const CHAT_BUTTON_TEST_ID = 'newChatById' as const;
/* About section */