Skip to content

Commit 1665e5d

Browse files
[AI4DSOC] Alert flyout code cleanup
1 parent 9c6fdd6 commit 1665e5d

25 files changed

Lines changed: 592 additions & 393 deletions

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2288,6 +2288,8 @@ x-pack/test/api_integration/apis/management/index_management/inference_endpoints
22882288
/x-pack/solutions/security/plugins/security_solution/public/common/components/formatted_date/index.tsx @elastic/security-threat-hunting-explore @elastic/security-threat-hunting-investigations
22892289
/x-pack/solutions/security/plugins/security_solution/public/common/components/formatted_number/index.tsx @elastic/security-threat-hunting-explore @elastic/security-threat-hunting-investigations
22902290

2291+
/x-pack/solutions/security/plugins/security_solution/public/flyout/ai_for_soc/components @elastic/security-threat-hunting-investigations @elastic/security-generative-ai
2292+
22912293
/x-pack/solutions/security/plugins/security_solution/server/routes @elastic/security-detections-response @elastic/security-threat-hunting
22922294
/x-pack/solutions/security/plugins/security_solution/server/utils @elastic/security-detections-response @elastic/security-threat-hunting
22932295
x-pack/test/security_solution_api_integration/test_suites/detections_response/utils @elastic/security-detections-response

x-pack/solutions/security/plugins/security_solution/public/flyout/ai_for_soc/components/ai_assistant_section.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export const AIAssistantSection = memo(({ getPromptContext }: AIAssistantSection
5252
<h2>{AI_ASSISTANT}</h2>
5353
</EuiTitle>
5454
<EuiSpacer size="s" />
55-
<Conversations id={eventId} />
55+
<Conversations alertId={eventId} />
5656
</EuiFlexItem>
5757
<EuiFlexItem data-test-subj={SUGGESTED_PROMPTS_SECTION_TEST_ID}>
5858
<EuiTitle size="xxs">

x-pack/solutions/security/plugins/security_solution/public/flyout/ai_for_soc/components/alert_summary/index.test.tsx renamed to x-pack/solutions/security/plugins/security_solution/public/flyout/ai_for_soc/components/alert_summary.test.tsx

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,18 @@
77

88
import React from 'react';
99
import { fireEvent, render, screen } from '@testing-library/react';
10-
import { AlertSummary } from '.';
10+
import {
11+
ALERT_SUMMARY_TEST_ID,
12+
AlertSummary,
13+
GENERATE_INSIGHTS_BUTTON_TEST_ID,
14+
REGENERATE_INSIGHTS_BUTTON_TEST_ID,
15+
} from './alert_summary';
1116
import type { PromptContext } from '@kbn/elastic-assistant';
12-
import { useAlertSummary } from '../../hooks/use_alert_summary';
17+
import { useAlertSummary } from '../hooks/use_alert_summary';
18+
import { MESSAGE_TEXT_TEST_ID } from './message_text';
19+
20+
jest.mock('../hooks/use_alert_summary');
1321

14-
jest.mock('../../hooks/use_alert_summary');
1522
const promptContext: PromptContext = {
1623
category: 'alert',
1724
description: 'Alert summary',
@@ -49,7 +56,7 @@ describe('AlertSummary', () => {
4956
});
5057
});
5158

52-
it('renders the loading state when `isLoading` is true', () => {
59+
it('should render the loading state when `isLoading` is true', () => {
5360
(useAlertSummary as jest.Mock).mockReturnValue({
5461
alertSummary: '',
5562
recommendedActions: '',
@@ -61,11 +68,13 @@ describe('AlertSummary', () => {
6168
replacements: {},
6269
},
6370
});
71+
6472
render(<AlertSummary {...defaultProps} />);
65-
expect(screen.getByTestId('generating-summary')).toBeInTheDocument();
73+
74+
expect(screen.getByTestId(ALERT_SUMMARY_TEST_ID)).toBeInTheDocument();
6675
});
6776

68-
it('renders the alert summary when `hasAlertSummary` is true and `isLoading` is false', () => {
77+
it('should render the alert summary when `hasAlertSummary` is true and `isLoading` is false', () => {
6978
(useAlertSummary as jest.Mock).mockReturnValue({
7079
alertSummary: 'Test alert summary',
7180
recommendedActions: 'Test recommended actions',
@@ -77,12 +86,16 @@ describe('AlertSummary', () => {
7786
replacements: {},
7887
},
7988
});
89+
8090
render(<AlertSummary {...defaultProps} />);
81-
expect(screen.getAllByTestId('messageText')[0]).toHaveTextContent('Test alert summary');
82-
expect(screen.getAllByTestId('messageText')[1]).toHaveTextContent('Test recommended actions');
91+
92+
expect(screen.getAllByTestId(MESSAGE_TEXT_TEST_ID)[0]).toHaveTextContent('Test alert summary');
93+
expect(screen.getAllByTestId(MESSAGE_TEXT_TEST_ID)[1]).toHaveTextContent(
94+
'Test recommended actions'
95+
);
8396
});
8497

85-
it('renders the generate button when `hasAlertSummary` is false', () => {
98+
it('should render the generate button when `hasAlertSummary` is false', () => {
8699
const fetchAISummary = jest.fn();
87100
(useAlertSummary as jest.Mock).mockReturnValue({
88101
alertSummary: '',
@@ -95,12 +108,15 @@ describe('AlertSummary', () => {
95108
replacements: {},
96109
},
97110
});
111+
98112
render(<AlertSummary {...defaultProps} />);
99-
fireEvent.click(screen.getByTestId('generateInsights'));
113+
114+
fireEvent.click(screen.getByTestId(GENERATE_INSIGHTS_BUTTON_TEST_ID));
115+
100116
expect(fetchAISummary).toHaveBeenCalled();
101117
});
102118

103-
it('renders the regenerate button when `hasAlertSummary` is true', () => {
119+
it('should render the regenerate button when `hasAlertSummary` is true', () => {
104120
const fetchAISummary = jest.fn();
105121
(useAlertSummary as jest.Mock).mockReturnValue({
106122
alertSummary: 'Test alert summary',
@@ -113,8 +129,11 @@ describe('AlertSummary', () => {
113129
replacements: {},
114130
},
115131
});
132+
116133
render(<AlertSummary {...defaultProps} />);
117-
fireEvent.click(screen.getByTestId('regenerateInsights'));
134+
135+
fireEvent.click(screen.getByTestId(REGENERATE_INSIGHTS_BUTTON_TEST_ID));
136+
118137
expect(fetchAISummary).toHaveBeenCalled();
119138
});
120139
});

x-pack/solutions/security/plugins/security_solution/public/flyout/ai_for_soc/components/alert_summary/index.tsx renamed to x-pack/solutions/security/plugins/security_solution/public/flyout/ai_for_soc/components/alert_summary.tsx

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,31 +18,71 @@ import {
1818
import type { PromptContext } from '@kbn/elastic-assistant';
1919
import { css } from '@emotion/react';
2020
import { AssistantIcon } from '@kbn/ai-assistant-icon';
21+
import { i18n } from '@kbn/i18n';
2122
import { ConnectorMissingCallout } from './connector_missing_callout';
22-
import { useAlertSummary } from '../../hooks/use_alert_summary';
23-
import { MessageText } from '../message_text';
24-
import * as i18n from '../../constants/translations';
23+
import { useAlertSummary } from '../hooks/use_alert_summary';
24+
import { MessageText } from './message_text';
2525

26-
interface Props {
26+
export const ALERT_SUMMARY_TEST_ID = 'ai-for-soc-alert-flyout-alert-summary';
27+
export const GENERATE_INSIGHTS_BUTTON_TEST_ID = 'ai-for-soc-alert-flyout-generate-insights-button';
28+
export const REGENERATE_INSIGHTS_BUTTON_TEST_ID =
29+
'ai-for-soc-alert-flyout-regenerate-insights-button';
30+
31+
const RECOMMENDED_ACTIONS = i18n.translate(
32+
'xpack.securitySolution.alertSummary.recommendedActions',
33+
{
34+
defaultMessage: 'Recommended actions',
35+
}
36+
);
37+
const GENERATING = i18n.translate('xpack.securitySolution.alertSummary.generating', {
38+
defaultMessage: 'Generating AI description and recommended actions.',
39+
});
40+
const GENERATE = i18n.translate('xpack.securitySolution.alertSummary.generate', {
41+
defaultMessage: 'Generate insights',
42+
});
43+
const REGENERATE = i18n.translate('xpack.securitySolution.alertSummary.regenerate', {
44+
defaultMessage: 'Regenerate insights',
45+
});
46+
47+
export interface AlertSummaryProps {
48+
/**
49+
* Id of the alert for which we will generate the summary
50+
*/
2751
alertId: string;
52+
/**
53+
* Value of useKibana.services.application.capabilities.management.kibana.settings
54+
*/
2855
canSeeAdvancedSettings: boolean;
56+
/**
57+
* Value of securitySolution:defaultAIConnector
58+
*/
2959
defaultConnectorId: string;
30-
isContextReady: boolean;
60+
/**
61+
* The context for the prompt
62+
*/
3163
promptContext: PromptContext;
64+
/**
65+
* Callback to set the value to the parent to be able to control the menu options
66+
*/
3267
setHasAlertSummary: React.Dispatch<React.SetStateAction<boolean>>;
68+
/**
69+
* If true we'll show anonymized values
70+
*/
3371
showAnonymizedValues?: boolean;
3472
}
3573

74+
/**
75+
* Component generating the AI summary for the visualized alert and showing in the alert summary section of the AI for SOC flyout.
76+
*/
3677
export const AlertSummary = memo(
3778
({
3879
alertId,
3980
canSeeAdvancedSettings,
4081
defaultConnectorId,
41-
isContextReady,
4282
promptContext,
4383
setHasAlertSummary,
4484
showAnonymizedValues,
45-
}: Props) => {
85+
}: AlertSummaryProps) => {
4686
const {
4787
alertSummary,
4888
recommendedActions,
@@ -54,13 +94,14 @@ export const AlertSummary = memo(
5494
} = useAlertSummary({
5595
alertId,
5696
defaultConnectorId,
57-
isContextReady,
5897
promptContext,
5998
showAnonymizedValues,
6099
});
100+
61101
useEffect(() => {
62102
setHasAlertSummary(hasAlertSummary);
63103
}, [hasAlertSummary, setHasAlertSummary]);
104+
64105
return (
65106
<>
66107
{hasAlertSummary ? (
@@ -72,9 +113,9 @@ export const AlertSummary = memo(
72113
font-style: italic;
73114
`}
74115
size="s"
75-
data-test-subj="generating-summary"
116+
data-test-subj={ALERT_SUMMARY_TEST_ID}
76117
>
77-
{i18n.GENERATING}
118+
{GENERATING}
78119
</EuiText>
79120
<EuiSkeletonText lines={3} size="s" />
80121
</>
@@ -93,7 +134,7 @@ export const AlertSummary = memo(
93134
<>
94135
<EuiPanel hasShadow={false} hasBorder paddingSize="s">
95136
<EuiText size="xs" color="subdued">
96-
{i18n.RECOMMENDED_ACTIONS}
137+
{RECOMMENDED_ACTIONS}
97138
</EuiText>
98139
<EuiSpacer size="s" />
99140
<MessageText content={recommendedActions} />
@@ -107,7 +148,7 @@ export const AlertSummary = memo(
107148
onClick={fetchAISummary}
108149
color="primary"
109150
size="m"
110-
data-test-subj="regenerateInsights"
151+
data-test-subj={REGENERATE_INSIGHTS_BUTTON_TEST_ID}
111152
isLoading={messageAndReplacements == null}
112153
>
113154
<EuiFlexGroup
@@ -119,7 +160,7 @@ export const AlertSummary = memo(
119160
<EuiFlexItem grow={false}>
120161
<AssistantIcon size="m" />
121162
</EuiFlexItem>
122-
<EuiFlexItem grow={false}>{i18n.REGENERATE}</EuiFlexItem>
163+
<EuiFlexItem grow={false}>{REGENERATE}</EuiFlexItem>
123164
</EuiFlexGroup>
124165
</EuiButton>
125166
</EuiFlexItem>
@@ -133,14 +174,14 @@ export const AlertSummary = memo(
133174
onClick={fetchAISummary}
134175
color="primary"
135176
size="m"
136-
data-test-subj="generateInsights"
177+
data-test-subj={GENERATE_INSIGHTS_BUTTON_TEST_ID}
137178
isLoading={messageAndReplacements == null}
138179
>
139180
<EuiFlexGroup gutterSize="s" alignItems="center">
140181
<EuiFlexItem grow={false}>
141182
<AssistantIcon size="m" />
142183
</EuiFlexItem>
143-
<EuiFlexItem grow={false}>{i18n.GENERATE}</EuiFlexItem>
184+
<EuiFlexItem grow={false}>{GENERATE}</EuiFlexItem>
144185
</EuiFlexGroup>
145186
</EuiButton>
146187
</EuiFlexItem>

x-pack/solutions/security/plugins/security_solution/public/flyout/ai_for_soc/components/alert_summary/connector_missing_callout.tsx

Lines changed: 0 additions & 42 deletions
This file was deleted.

x-pack/solutions/security/plugins/security_solution/public/flyout/ai_for_soc/components/ai_summary_section.test.tsx renamed to x-pack/solutions/security/plugins/security_solution/public/flyout/ai_for_soc/components/alert_summary_section.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import React from 'react';
99
import { render } from '@testing-library/react';
1010
import { useAIForSOCDetailsContext } from '../context';
1111
import { TestProviders } from '../../../common/mock';
12-
import { AISummarySection, ALERT_SUMMARY_SECTION_TEST_ID } from './ai_summary_section';
12+
import { ALERT_SUMMARY_SECTION_TEST_ID, AlertSummarySection } from './alert_summary_section';
1313
import { ALERT_SUMMARY_OPTIONS_MENU_BUTTON_TEST_ID } from './settings_menu';
1414
import { useKibana as mockUseKibana } from '../../../common/lib/kibana/__mocks__';
1515

@@ -41,7 +41,7 @@ jest.mock('../../../common/lib/kibana', () => {
4141
};
4242
});
4343

44-
describe('AISummarySection', () => {
44+
describe('AlertSummarySection', () => {
4545
it('should render the AI summary section', () => {
4646
(useAIForSOCDetailsContext as jest.Mock).mockReturnValue({
4747
eventId: 'eventId',
@@ -52,7 +52,7 @@ describe('AISummarySection', () => {
5252

5353
const { getByTestId } = render(
5454
<TestProviders>
55-
<AISummarySection getPromptContext={getPromptContext} />
55+
<AlertSummarySection getPromptContext={getPromptContext} />
5656
</TestProviders>
5757
);
5858

x-pack/solutions/security/plugins/security_solution/public/flyout/ai_for_soc/components/ai_summary_section.tsx renamed to x-pack/solutions/security/plugins/security_solution/public/flyout/ai_for_soc/components/alert_summary_section.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const AI_SUMMARY = i18n.translate('xpack.securitySolution.alertSummary.aiSummary
2121
defaultMessage: 'AI summary',
2222
});
2323

24-
export interface AISummarySectionProps {
24+
export interface AlertSummarySectionProps {
2525
/**
2626
* The Elastic AI Assistant will invoke this function to retrieve the context data,
2727
* which will be included in a prompt (e.g. the contents of an alert or an event)
@@ -30,18 +30,17 @@ export interface AISummarySectionProps {
3030
}
3131

3232
/**
33-
* AI summary section of the AI for SOC alert summary alert flyout.
33+
* Alert summary section of the AI for SOC alert summary alert flyout.
3434
*/
35-
export const AISummarySection = memo(({ getPromptContext }: AISummarySectionProps) => {
35+
export const AlertSummarySection = memo(({ getPromptContext }: AlertSummarySectionProps) => {
3636
const [hasAlertSummary, setHasAlertSummary] = useState(false);
3737

3838
const {
3939
application: { capabilities },
4040
uiSettings,
4141
} = useKibana().services;
4242

43-
const { eventId, dataFormattedForFieldBrowser, showAnonymizedValues } =
44-
useAIForSOCDetailsContext();
43+
const { eventId, showAnonymizedValues } = useAIForSOCDetailsContext();
4544

4645
const canSeeAdvancedSettings = capabilities.management.kibana.settings ?? false;
4746
const defaultConnectorId = uiSettings.get<string>(DEFAULT_AI_CONNECTOR);
@@ -74,7 +73,6 @@ export const AISummarySection = memo(({ getPromptContext }: AISummarySectionProp
7473
alertId={eventId}
7574
canSeeAdvancedSettings={canSeeAdvancedSettings}
7675
defaultConnectorId={defaultConnectorId}
77-
isContextReady={(dataFormattedForFieldBrowser ?? []).length > 0}
7876
promptContext={promptContext}
7977
setHasAlertSummary={setHasAlertSummary}
8078
showAnonymizedValues={showAnonymizedValues}
@@ -83,4 +81,4 @@ export const AISummarySection = memo(({ getPromptContext }: AISummarySectionProp
8381
);
8482
});
8583

86-
AISummarySection.displayName = 'AISummarySection';
84+
AlertSummarySection.displayName = 'AlertSummarySection';

0 commit comments

Comments
 (0)