Skip to content

Commit c283ca5

Browse files
[Security Solution] add expandable flyout description section to overview tab (#153706)
1 parent 88b9f1a commit c283ca5

27 files changed

+1200
-138
lines changed

packages/kbn-expandable-flyout/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,5 @@ export interface Panel {
3939
/**
4040
* Width used when rendering the panel
4141
*/
42-
width: number; // TODO remove this, the width shouldn't be a property of a panel, but handled at the flyout level
42+
width: number; // TODO remove this, see https://github.com/elastic/security-team/issues/6247
4343
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import { upperFirst } from 'lodash';
9+
import {
10+
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE,
11+
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE_VALUE,
12+
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY,
13+
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY_VALUE,
14+
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_TITLE,
15+
} from '../../../screens/document_expandable_flyout';
16+
import { expandFirstAlertExpandableFlyout } from '../../../tasks/document_expandable_flyout';
17+
import { cleanKibana } from '../../../tasks/common';
18+
import { login, visit } from '../../../tasks/login';
19+
import { createRule } from '../../../tasks/api_calls/rules';
20+
import { getNewRule } from '../../../objects/rule';
21+
import { ALERTS_URL } from '../../../urls/navigation';
22+
import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule';
23+
24+
// Skipping these for now as the feature is protected behind a feature flag set to false by default
25+
// To run the tests locally, add 'securityFlyoutEnabled' in the Cypress config.ts here https://github.com/elastic/kibana/blob/main/x-pack/test/security_solution_cypress/config.ts#L50
26+
describe.skip(
27+
'Alert details expandable flyout right panel header',
28+
{ testIsolation: false },
29+
() => {
30+
const rule = getNewRule();
31+
32+
before(() => {
33+
cleanKibana();
34+
login();
35+
createRule(rule);
36+
visit(ALERTS_URL);
37+
waitForAlertsToPopulate();
38+
expandFirstAlertExpandableFlyout();
39+
});
40+
41+
it('should display correct title in header', () => {
42+
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_TITLE)
43+
.should('be.visible')
44+
.and('have.text', rule.name);
45+
});
46+
47+
it('should display risk score in header', () => {
48+
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE).should('be.visible');
49+
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE_VALUE)
50+
.should('be.visible')
51+
.and('have.text', rule.risk_score);
52+
});
53+
54+
it('should display severity in header', () => {
55+
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY).should('be.visible');
56+
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY_VALUE)
57+
.should('be.visible')
58+
.and('have.text', upperFirst(rule.severity));
59+
});
60+
}
61+
);

x-pack/plugins/security_solution/cypress/e2e/detection_alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts

Lines changed: 95 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
* 2.0.
66
*/
77

8-
import { upperFirst } from 'lodash';
98
import {
109
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS,
1110
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE,
@@ -16,15 +15,18 @@ import {
1615
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS,
1716
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_EXPAND_ICON,
1817
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_TITLE,
19-
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE,
20-
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE_VALUE,
21-
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY,
22-
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY_VALUE,
23-
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_TITLE,
18+
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_HEADER,
19+
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_CONTENT,
20+
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE,
21+
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE,
22+
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_DETAILS,
23+
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_EXPAND_BUTTON,
24+
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_DETAILS,
2425
} from '../../../screens/document_expandable_flyout';
2526
import {
2627
expandFirstAlertExpandableFlyout,
2728
openOverviewTab,
29+
toggleOverviewTabDescriptionSection,
2830
} from '../../../tasks/document_expandable_flyout';
2931
import { cleanKibana } from '../../../tasks/common';
3032
import { login, visit } from '../../../tasks/login';
@@ -51,74 +53,105 @@ describe.skip(
5153
openOverviewTab();
5254
});
5355

54-
it('should display correct title in header', () => {
55-
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_TITLE)
56-
.should('be.visible')
57-
.and('have.text', rule.name);
58-
});
59-
60-
it('should display risk score in header', () => {
61-
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE).should('be.visible');
62-
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE_VALUE)
63-
.should('be.visible')
64-
.and('have.text', rule.risk_score);
65-
});
66-
67-
it('should display severity in header', () => {
68-
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY).should('be.visible');
69-
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY_VALUE)
70-
.should('be.visible')
71-
.and('have.text', upperFirst(rule.severity));
72-
});
73-
74-
it('should display mitre attack', () => {
75-
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE)
76-
.should('be.visible')
77-
// @ts-ignore
78-
.and('contain.text', rule.threat[0].framework);
79-
80-
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS)
81-
.should('be.visible')
82-
// @ts-ignore
83-
.and('contain.text', rule.threat[0].technique[0].name)
84-
// @ts-ignore
85-
.and('contain.text', rule.threat[0].tactic.name);
86-
});
56+
describe('description section', () => {
57+
it('should display description section header and content', () => {
58+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_HEADER)
59+
.should('be.visible')
60+
.and('have.text', 'Description');
61+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_CONTENT).should(
62+
'be.visible'
63+
);
64+
});
8765

88-
it('should display highlighted fields', () => {
89-
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS).within(() => {
90-
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_EXPAND_ICON)
66+
it('should display document description and expand button', () => {
67+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE)
9168
.should('be.visible')
92-
.click();
93-
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_TITLE)
69+
.and('have.text', 'Rule description');
70+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_DETAILS)
9471
.should('be.visible')
95-
.and('have.text', 'Highlighted fields');
96-
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_DETAILS).should(
97-
'be.visible'
72+
.and('have.text', rule.description);
73+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_EXPAND_BUTTON)
74+
.should('be.visible')
75+
.and('have.text', 'Expand');
76+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_EXPAND_BUTTON).click();
77+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_EXPAND_BUTTON).should(
78+
'have.text',
79+
'Collapse'
9880
);
81+
});
9982

100-
// close highlighted fields to reset the view for next test
101-
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_EXPAND_ICON)
83+
it('should display reason', () => {
84+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE)
85+
.should('be.visible')
86+
.and('have.text', 'Alert reason');
87+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_DETAILS)
10288
.should('be.visible')
103-
.click();
89+
.and('contain.text', rule.name);
10490
});
105-
});
10691

107-
it('should navigate to table tab when clicking on highlighted fields view button', () => {
108-
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS).within(() => {
109-
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_EXPAND_ICON)
92+
it('should display mitre attack', () => {
93+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE).should('be.visible');
94+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS).should('be.visible');
95+
});
96+
97+
it('should display mitre attack', () => {
98+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE)
11099
.should('be.visible')
111-
.click();
112-
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_GO_TO_TABLE_LINK)
100+
// @ts-ignore
101+
.and('contain.text', rule.threat[0].framework);
102+
103+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS)
113104
.should('be.visible')
114-
.click();
105+
// @ts-ignore
106+
.and('contain.text', rule.threat[0].technique[0].name)
107+
// @ts-ignore
108+
.and('contain.text', rule.threat[0].tactic.name);
115109
});
110+
});
116111

117-
// the table component is rendered within a dom element with overflow, so Cypress isn't finding it
118-
// this next line is a hack that scrolls to a specific element in the table
119-
// (in the middle of it vertically) to ensure Cypress finds it
120-
cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_EVENT_TYPE_ROW).scrollIntoView();
121-
cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_CONTENT).should('be.visible');
112+
describe('investigation section', () => {
113+
before(() => {
114+
toggleOverviewTabDescriptionSection();
115+
});
116+
117+
it('should display highlighted fields', () => {
118+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS)
119+
.scrollIntoView()
120+
.within(() => {
121+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_EXPAND_ICON)
122+
.should('be.visible')
123+
.click();
124+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_TITLE)
125+
.should('be.visible')
126+
.and('have.text', 'Highlighted fields');
127+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_DETAILS).should(
128+
'be.visible'
129+
);
130+
131+
// close highlighted fields to reset the view for next test
132+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_EXPAND_ICON)
133+
.should('be.visible')
134+
.click();
135+
});
136+
});
137+
it('should navigate to table tab when clicking on highlighted fields view button', () => {
138+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS)
139+
.scrollIntoView()
140+
.within(() => {
141+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_EXPAND_ICON)
142+
.should('be.visible')
143+
.click();
144+
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_GO_TO_TABLE_LINK)
145+
.should('be.visible')
146+
.click();
147+
});
148+
149+
// the table component is rendered within a dom element with overflow, so Cypress isn't finding it
150+
// this next line is a hack that scrolls to a specific element in the table
151+
// (in the middle of it vertically) to ensure Cypress finds it
152+
cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_EVENT_TYPE_ROW).scrollIntoView();
153+
cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_CONTENT).should('be.visible');
154+
});
122155
});
123156
}
124157
);

x-pack/plugins/security_solution/cypress/screens/document_expandable_flyout.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ import {
3535
} from '../../public/flyout/right/tabs/test_ids';
3636
import {
3737
COLLAPSE_DETAILS_BUTTON_TEST_ID,
38+
DESCRIPTION_DETAILS_TEST_ID,
39+
DESCRIPTION_EXPAND_BUTTON_TEST_ID,
40+
DESCRIPTION_SECTION_CONTENT_TEST_ID,
41+
DESCRIPTION_SECTION_HEADER_TEST_ID,
42+
DESCRIPTION_TITLE_TEST_ID,
3843
EXPAND_DETAILS_BUTTON_TEST_ID,
3944
FLYOUT_HEADER_RISK_SCORE_TITLE_TEST_ID,
4045
FLYOUT_HEADER_RISK_SCORE_VALUE_TEST_ID,
@@ -48,6 +53,8 @@ import {
4853
HIGHLIGHTED_FIELDS_TEST_ID,
4954
MITRE_ATTACK_DETAILS_TEST_ID,
5055
MITRE_ATTACK_TITLE_TEST_ID,
56+
REASON_DETAILS_TEST_ID,
57+
REASON_TITLE_TEST_ID,
5158
} from '../../public/flyout/right/components/test_ids';
5259
import { getClassSelector, getDataTestSubjectSelector } from '../helpers/common';
5360

@@ -106,6 +113,21 @@ export const DOCUMENT_DETAILS_FLYOUT_HISTORY_TAB_CONTENT = getDataTestSubjectSel
106113

107114
/* Overview tab */
108115

116+
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_HEADER =
117+
getDataTestSubjectSelector(DESCRIPTION_SECTION_HEADER_TEST_ID);
118+
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_CONTENT =
119+
getDataTestSubjectSelector(DESCRIPTION_SECTION_CONTENT_TEST_ID);
120+
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE =
121+
getDataTestSubjectSelector(DESCRIPTION_TITLE_TEST_ID);
122+
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_DETAILS = getDataTestSubjectSelector(
123+
DESCRIPTION_DETAILS_TEST_ID
124+
);
125+
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_EXPAND_BUTTON =
126+
getDataTestSubjectSelector(DESCRIPTION_EXPAND_BUTTON_TEST_ID);
127+
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE =
128+
getDataTestSubjectSelector(REASON_TITLE_TEST_ID);
129+
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_DETAILS =
130+
getDataTestSubjectSelector(REASON_DETAILS_TEST_ID);
109131
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE = getDataTestSubjectSelector(
110132
MITRE_ATTACK_TITLE_TEST_ID
111133
);

x-pack/plugins/security_solution/cypress/tasks/document_expandable_flyout.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
DOCUMENT_DETAILS_FLYOUT_INVESTIGATIONS_TAB,
1515
DOCUMENT_DETAILS_FLYOUT_JSON_TAB,
1616
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB,
17+
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_HEADER,
1718
DOCUMENT_DETAILS_FLYOUT_TABLE_TAB,
1819
DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_CLEAR_FILTER,
1920
DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_FILTER,
@@ -60,6 +61,15 @@ export const scrollWithinDocumentDetailsExpandableFlyoutRightSection = (x: numbe
6061
export const openOverviewTab = () =>
6162
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB).should('be.visible').click();
6263

64+
/**
65+
* Toggle the Overview tab description section in the document details expandable flyout right section
66+
*/
67+
export const toggleOverviewTabDescriptionSection = () =>
68+
cy
69+
.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_HEADER)
70+
.should('be.visible')
71+
.click();
72+
6373
/**
6474
* Open the Table tab in the document details expandable flyout right section
6575
*/

x-pack/plugins/security_solution/public/flyout/index.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,19 @@ import type { LeftPanelProps } from './left';
1414
import { LeftPanel, LeftPanelKey } from './left';
1515
import { LeftPanelProvider } from './left/context';
1616

17+
// TODO these should be replaced by a more dynamic solution
18+
// see https://github.com/elastic/security-team/issues/6247
19+
export const RIGHT_SECTION_WIDTH = 500;
20+
export const LEFT_SECTION_WIDTH = 1000;
21+
1722
/**
1823
* List of all panels that will be used within the document details expandable flyout.
1924
* This needs to be passed to the expandable flyout registeredPanels property.
2025
*/
2126
export const expandableFlyoutDocumentsPanels: ExpandableFlyoutProps['registeredPanels'] = [
2227
{
2328
key: RightPanelKey,
24-
width: 500,
29+
width: RIGHT_SECTION_WIDTH,
2530
component: (props) => (
2631
<RightPanelProvider {...(props as RightPanelProps).params}>
2732
<RightPanel path={props.path as RightPanelProps['path']} />
@@ -30,7 +35,7 @@ export const expandableFlyoutDocumentsPanels: ExpandableFlyoutProps['registeredP
3035
},
3136
{
3237
key: LeftPanelKey,
33-
width: 1000,
38+
width: LEFT_SECTION_WIDTH,
3439
component: (props) => (
3540
<LeftPanelProvider {...(props as LeftPanelProps).params}>
3641
<LeftPanel path={props.path as LeftPanelProps['path']} />

0 commit comments

Comments
 (0)