Skip to content

Commit

Permalink
[Security Solution] add expandable flyout description section to over…
Browse files Browse the repository at this point in the history
…view tab (elastic#153706)
  • Loading branch information
PhilippeOberti authored and jgowdyelastic committed Mar 30, 2023
1 parent fafa627 commit 9716d1e
Show file tree
Hide file tree
Showing 27 changed files with 1,200 additions and 138 deletions.
2 changes: 1 addition & 1 deletion packages/kbn-expandable-flyout/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@ export interface Panel {
/**
* Width used when rendering the panel
*/
width: number; // TODO remove this, the width shouldn't be a property of a panel, but handled at the flyout level
width: number; // TODO remove this, see https://github.com/elastic/security-team/issues/6247
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* 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 { upperFirst } from 'lodash';
import {
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE,
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE_VALUE,
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY,
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY_VALUE,
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_TITLE,
} from '../../../screens/document_expandable_flyout';
import { expandFirstAlertExpandableFlyout } from '../../../tasks/document_expandable_flyout';
import { cleanKibana } from '../../../tasks/common';
import { login, visit } from '../../../tasks/login';
import { createRule } from '../../../tasks/api_calls/rules';
import { getNewRule } from '../../../objects/rule';
import { ALERTS_URL } from '../../../urls/navigation';
import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule';

// Skipping these for now as the feature is protected behind a feature flag set to false by default
// 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
describe.skip(
'Alert details expandable flyout right panel header',
{ testIsolation: false },
() => {
const rule = getNewRule();

before(() => {
cleanKibana();
login();
createRule(rule);
visit(ALERTS_URL);
waitForAlertsToPopulate();
expandFirstAlertExpandableFlyout();
});

it('should display correct title in header', () => {
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_TITLE)
.should('be.visible')
.and('have.text', rule.name);
});

it('should display risk score in header', () => {
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE).should('be.visible');
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE_VALUE)
.should('be.visible')
.and('have.text', rule.risk_score);
});

it('should display severity in header', () => {
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY).should('be.visible');
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY_VALUE)
.should('be.visible')
.and('have.text', upperFirst(rule.severity));
});
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* 2.0.
*/

import { upperFirst } from 'lodash';
import {
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS,
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE,
Expand All @@ -16,15 +15,18 @@ import {
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS,
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_EXPAND_ICON,
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_TITLE,
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE,
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE_VALUE,
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY,
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY_VALUE,
DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_TITLE,
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_HEADER,
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_CONTENT,
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE,
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE,
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_DETAILS,
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_EXPAND_BUTTON,
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_DETAILS,
} from '../../../screens/document_expandable_flyout';
import {
expandFirstAlertExpandableFlyout,
openOverviewTab,
toggleOverviewTabDescriptionSection,
} from '../../../tasks/document_expandable_flyout';
import { cleanKibana } from '../../../tasks/common';
import { login, visit } from '../../../tasks/login';
Expand All @@ -51,74 +53,105 @@ describe.skip(
openOverviewTab();
});

it('should display correct title in header', () => {
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_TITLE)
.should('be.visible')
.and('have.text', rule.name);
});

it('should display risk score in header', () => {
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE).should('be.visible');
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_RISK_SCORE_VALUE)
.should('be.visible')
.and('have.text', rule.risk_score);
});

it('should display severity in header', () => {
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY).should('be.visible');
cy.get(DOCUMENT_DETAILS_OVERVIEW_TAB_HEADER_SEVERITY_VALUE)
.should('be.visible')
.and('have.text', upperFirst(rule.severity));
});

it('should display mitre attack', () => {
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE)
.should('be.visible')
// @ts-ignore
.and('contain.text', rule.threat[0].framework);

cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS)
.should('be.visible')
// @ts-ignore
.and('contain.text', rule.threat[0].technique[0].name)
// @ts-ignore
.and('contain.text', rule.threat[0].tactic.name);
});
describe('description section', () => {
it('should display description section header and content', () => {
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_HEADER)
.should('be.visible')
.and('have.text', 'Description');
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_CONTENT).should(
'be.visible'
);
});

it('should display highlighted fields', () => {
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS).within(() => {
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_EXPAND_ICON)
it('should display document description and expand button', () => {
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE)
.should('be.visible')
.click();
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_TITLE)
.and('have.text', 'Rule description');
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_DETAILS)
.should('be.visible')
.and('have.text', 'Highlighted fields');
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_DETAILS).should(
'be.visible'
.and('have.text', rule.description);
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_EXPAND_BUTTON)
.should('be.visible')
.and('have.text', 'Expand');
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_EXPAND_BUTTON).click();
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_EXPAND_BUTTON).should(
'have.text',
'Collapse'
);
});

// close highlighted fields to reset the view for next test
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_EXPAND_ICON)
it('should display reason', () => {
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE)
.should('be.visible')
.and('have.text', 'Alert reason');
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_DETAILS)
.should('be.visible')
.click();
.and('contain.text', rule.name);
});
});

it('should navigate to table tab when clicking on highlighted fields view button', () => {
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS).within(() => {
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_EXPAND_ICON)
it('should display mitre attack', () => {
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE).should('be.visible');
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS).should('be.visible');
});

it('should display mitre attack', () => {
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE)
.should('be.visible')
.click();
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_GO_TO_TABLE_LINK)
// @ts-ignore
.and('contain.text', rule.threat[0].framework);

cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS)
.should('be.visible')
.click();
// @ts-ignore
.and('contain.text', rule.threat[0].technique[0].name)
// @ts-ignore
.and('contain.text', rule.threat[0].tactic.name);
});
});

// the table component is rendered within a dom element with overflow, so Cypress isn't finding it
// this next line is a hack that scrolls to a specific element in the table
// (in the middle of it vertically) to ensure Cypress finds it
cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_EVENT_TYPE_ROW).scrollIntoView();
cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_CONTENT).should('be.visible');
describe('investigation section', () => {
before(() => {
toggleOverviewTabDescriptionSection();
});

it('should display highlighted fields', () => {
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS)
.scrollIntoView()
.within(() => {
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_EXPAND_ICON)
.should('be.visible')
.click();
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_TITLE)
.should('be.visible')
.and('have.text', 'Highlighted fields');
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_DETAILS).should(
'be.visible'
);

// close highlighted fields to reset the view for next test
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_EXPAND_ICON)
.should('be.visible')
.click();
});
});
it('should navigate to table tab when clicking on highlighted fields view button', () => {
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS)
.scrollIntoView()
.within(() => {
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_EXPAND_ICON)
.should('be.visible')
.click();
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_GO_TO_TABLE_LINK)
.should('be.visible')
.click();
});

// the table component is rendered within a dom element with overflow, so Cypress isn't finding it
// this next line is a hack that scrolls to a specific element in the table
// (in the middle of it vertically) to ensure Cypress finds it
cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_EVENT_TYPE_ROW).scrollIntoView();
cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_CONTENT).should('be.visible');
});
});
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ import {
} from '../../public/flyout/right/tabs/test_ids';
import {
COLLAPSE_DETAILS_BUTTON_TEST_ID,
DESCRIPTION_DETAILS_TEST_ID,
DESCRIPTION_EXPAND_BUTTON_TEST_ID,
DESCRIPTION_SECTION_CONTENT_TEST_ID,
DESCRIPTION_SECTION_HEADER_TEST_ID,
DESCRIPTION_TITLE_TEST_ID,
EXPAND_DETAILS_BUTTON_TEST_ID,
FLYOUT_HEADER_RISK_SCORE_TITLE_TEST_ID,
FLYOUT_HEADER_RISK_SCORE_VALUE_TEST_ID,
Expand All @@ -48,6 +53,8 @@ import {
HIGHLIGHTED_FIELDS_TEST_ID,
MITRE_ATTACK_DETAILS_TEST_ID,
MITRE_ATTACK_TITLE_TEST_ID,
REASON_DETAILS_TEST_ID,
REASON_TITLE_TEST_ID,
} from '../../public/flyout/right/components/test_ids';
import { getClassSelector, getDataTestSubjectSelector } from '../helpers/common';

Expand Down Expand Up @@ -106,6 +113,21 @@ export const DOCUMENT_DETAILS_FLYOUT_HISTORY_TAB_CONTENT = getDataTestSubjectSel

/* Overview tab */

export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_HEADER =
getDataTestSubjectSelector(DESCRIPTION_SECTION_HEADER_TEST_ID);
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_CONTENT =
getDataTestSubjectSelector(DESCRIPTION_SECTION_CONTENT_TEST_ID);
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE =
getDataTestSubjectSelector(DESCRIPTION_TITLE_TEST_ID);
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_DETAILS = getDataTestSubjectSelector(
DESCRIPTION_DETAILS_TEST_ID
);
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_EXPAND_BUTTON =
getDataTestSubjectSelector(DESCRIPTION_EXPAND_BUTTON_TEST_ID);
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE =
getDataTestSubjectSelector(REASON_TITLE_TEST_ID);
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_DETAILS =
getDataTestSubjectSelector(REASON_DETAILS_TEST_ID);
export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE = getDataTestSubjectSelector(
MITRE_ATTACK_TITLE_TEST_ID
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
DOCUMENT_DETAILS_FLYOUT_INVESTIGATIONS_TAB,
DOCUMENT_DETAILS_FLYOUT_JSON_TAB,
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB,
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_HEADER,
DOCUMENT_DETAILS_FLYOUT_TABLE_TAB,
DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_CLEAR_FILTER,
DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_FILTER,
Expand Down Expand Up @@ -60,6 +61,15 @@ export const scrollWithinDocumentDetailsExpandableFlyoutRightSection = (x: numbe
export const openOverviewTab = () =>
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB).should('be.visible').click();

/**
* Toggle the Overview tab description section in the document details expandable flyout right section
*/
export const toggleOverviewTabDescriptionSection = () =>
cy
.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_SECTION_HEADER)
.should('be.visible')
.click();

/**
* Open the Table tab in the document details expandable flyout right section
*/
Expand Down
9 changes: 7 additions & 2 deletions x-pack/plugins/security_solution/public/flyout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,19 @@ import type { LeftPanelProps } from './left';
import { LeftPanel, LeftPanelKey } from './left';
import { LeftPanelProvider } from './left/context';

// TODO these should be replaced by a more dynamic solution
// see https://github.com/elastic/security-team/issues/6247
export const RIGHT_SECTION_WIDTH = 500;
export const LEFT_SECTION_WIDTH = 1000;

/**
* List of all panels that will be used within the document details expandable flyout.
* This needs to be passed to the expandable flyout registeredPanels property.
*/
export const expandableFlyoutDocumentsPanels: ExpandableFlyoutProps['registeredPanels'] = [
{
key: RightPanelKey,
width: 500,
width: RIGHT_SECTION_WIDTH,
component: (props) => (
<RightPanelProvider {...(props as RightPanelProps).params}>
<RightPanel path={props.path as RightPanelProps['path']} />
Expand All @@ -30,7 +35,7 @@ export const expandableFlyoutDocumentsPanels: ExpandableFlyoutProps['registeredP
},
{
key: LeftPanelKey,
width: 1000,
width: LEFT_SECTION_WIDTH,
component: (props) => (
<LeftPanelProvider {...(props as LeftPanelProps).params}>
<LeftPanel path={props.path as LeftPanelProps['path']} />
Expand Down
Loading

0 comments on commit 9716d1e

Please sign in to comment.