From 6ee79558ab9b8b3c29a4603a88c981ee34587eeb Mon Sep 17 00:00:00 2001 From: Pablo Machado Date: Tue, 29 Jun 2021 17:00:30 +0200 Subject: [PATCH] [Security Solution][Detections] Fix Investigation guide format issues (#101609) * Fix 'Detection' / 'Investigation Guide' UI broken when it contains long words * Fix investigation guide is not formatted under Alert details flyout * Add LineClamp to investigation guide field * It enhances LineClamp to support a react node instead of only text Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../event_details/alert_summary_view.tsx | 5 ++- .../components/line_clamp/index.test.tsx | 39 +++++++++-------- .../common/components/line_clamp/index.tsx | 42 +++++++++++-------- .../rules/step_about_rule_details/index.tsx | 1 + .../components/flyout/header/index.tsx | 5 ++- .../event_details/expandable_event.tsx | 2 +- 6 files changed, 55 insertions(+), 39 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx index d89f44542318..be45e16e456d 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx @@ -36,6 +36,7 @@ import { DESTINATION_IP_FIELD_NAME, SOURCE_IP_FIELD_NAME } from '../../../networ import { SummaryView } from './summary_view'; import { AlertSummaryRow, getSummaryColumns, SummaryRow } from './helpers'; import { useRuleWithFallback } from '../../../detections/containers/detection_engine/rules/use_rule_with_fallback'; +import { MarkdownRenderer } from '../markdown_editor'; import { LineClamp } from '../line_clamp'; import { endpointAlertCheck } from '../../utils/endpoint_alert_check'; @@ -221,7 +222,9 @@ const AlertSummaryViewComponent: React.FC<{ {i18n.INVESTIGATION_GUIDE} - + + {maybeRule.note} + )} diff --git a/x-pack/plugins/security_solution/public/common/components/line_clamp/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/line_clamp/index.test.tsx index 73f46a177103..933517c49690 100644 --- a/x-pack/plugins/security_solution/public/common/components/line_clamp/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/line_clamp/index.test.tsx @@ -16,25 +16,30 @@ describe('LineClamp', () => { describe('no overflow', () => { test('it does NOT render the expanded line clamp when isOverflow is falsy', () => { - const wrapper = mount(); + const wrapper = mount({message}); expect(wrapper.find('[data-test-subj="expanded-line-clamp"]').exists()).toBe(false); }); test('it does NOT render the styled line clamp expanded when isOverflow is falsy', () => { - const wrapper = mount(); + const wrapper = mount({message}); expect(wrapper.find('[data-test-subj="styled-line-clamp"]').exists()).toBe(false); }); - test('it renders the default line clamp when isOverflow is falsy', () => { - const wrapper = mount(); + test('it renders the children when isOverflow is falsy', () => { + const TestComponent = () => <>{message}; + const wrapper = mount( + + + + ); - expect(wrapper.find('[data-test-subj="default-line-clamp"]').first().text()).toBe(message); + expect(wrapper.childAt(0).type()).toBe(TestComponent); }); test('it does NOT render the `Read More` button when isOverflow is falsy', () => { - const wrapper = mount(); + const wrapper = mount({message}); expect(wrapper.find('[data-test-subj="summary-view-readmore"]').exists()).toBe(false); }); @@ -59,25 +64,25 @@ describe('LineClamp', () => { }); test('it does NOT render the expanded line clamp by default when isOverflow is true', () => { - const wrapper = mount(); + const wrapper = mount({message}); expect(wrapper.find('[data-test-subj="expanded-line-clamp"]').exists()).toBe(false); }); test('it renders the styled line clamp when isOverflow is true', () => { - const wrapper = mount(); + const wrapper = mount({message}); expect(wrapper.find('[data-test-subj="styled-line-clamp"]').first().text()).toBe(message); }); test('it does NOT render the default line clamp when isOverflow is true', () => { - const wrapper = mount(); + const wrapper = mount({message}); expect(wrapper.find('[data-test-subj="default-line-clamp"]').exists()).toBe(false); }); test('it renders the `Read More` button with the expected (default) text when isOverflow is true', () => { - const wrapper = mount(); + const wrapper = mount({message}); expect(wrapper.find('[data-test-subj="summary-view-readmore"]').first().text()).toBe( 'Read More' @@ -86,7 +91,7 @@ describe('LineClamp', () => { describe('clicking the Read More button', () => { test('it displays the `Read Less` button text after the user clicks the `Read More` button when isOverflow is true', () => { - const wrapper = mount(); + const wrapper = mount({message}); wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click'); wrapper.update(); @@ -97,7 +102,7 @@ describe('LineClamp', () => { }); test('it renders the expanded content after the user clicks the `Read More` button when isOverflow is true', () => { - const wrapper = mount(); + const wrapper = mount({message}); wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click'); wrapper.update(); @@ -107,7 +112,7 @@ describe('LineClamp', () => { }); test('it renders the expanded content with a max-height of one third the view height when isOverflow is true', () => { - const wrapper = mount(); + const wrapper = mount({message}); wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click'); wrapper.update(); @@ -119,7 +124,7 @@ describe('LineClamp', () => { }); test('it automatically vertically scrolls the content when isOverflow is true', () => { - const wrapper = mount(); + const wrapper = mount({message}); wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click'); wrapper.update(); @@ -131,7 +136,7 @@ describe('LineClamp', () => { }); test('it does NOT render the styled line clamp after the user clicks the `Read More` button when isOverflow is true', () => { - const wrapper = mount(); + const wrapper = mount({message}); wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click'); wrapper.update(); @@ -140,7 +145,7 @@ describe('LineClamp', () => { }); test('it does NOT render the default line clamp after the user clicks the `Read More` button when isOverflow is true', () => { - const wrapper = mount(); + const wrapper = mount({message}); wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click'); wrapper.update(); @@ -149,7 +154,7 @@ describe('LineClamp', () => { }); test('it once again displays the `Read More` button text after the user clicks the `Read Less` when isOverflow is true', () => { - const wrapper = mount(); + const wrapper = mount({message}); wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click'); wrapper.update(); // 1st toggle diff --git a/x-pack/plugins/security_solution/public/common/components/line_clamp/index.tsx b/x-pack/plugins/security_solution/public/common/components/line_clamp/index.tsx index d8895490d1e0..372e7fd466b0 100644 --- a/x-pack/plugins/security_solution/public/common/components/line_clamp/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/line_clamp/index.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { EuiButtonEmpty, EuiText } from '@elastic/eui'; -import React, { useRef, useState, useEffect, useCallback } from 'react'; +import { EuiButtonEmpty } from '@elastic/eui'; +import React, { useRef, useState, useEffect, useCallback, ReactNode } from 'react'; import styled from 'styled-components'; import * as i18n from './translations'; @@ -36,9 +36,9 @@ const StyledLineClamp = styled.div<{ lineClampHeight: number }>` `; const LineClampComponent: React.FC<{ - content?: string | null; + children: ReactNode; lineClampHeight?: number; -}> = ({ content, lineClampHeight = LINE_CLAMP_HEIGHT }) => { +}> = ({ children, lineClampHeight = LINE_CLAMP_HEIGHT }) => { const [isOverflow, setIsOverflow] = useState(null); const [isExpanded, setIsExpanded] = useState(null); const descriptionRef = useRef(null); @@ -47,7 +47,7 @@ const LineClampComponent: React.FC<{ }, []); useEffect(() => { - if (content != null && descriptionRef?.current?.clientHeight != null) { + if (descriptionRef?.current?.clientHeight != null) { if ( (descriptionRef?.current?.scrollHeight ?? 0) > (descriptionRef?.current?.clientHeight ?? 0) ) { @@ -55,38 +55,44 @@ const LineClampComponent: React.FC<{ } if ( - ((content == null || descriptionRef?.current?.scrollHeight) ?? 0) <= - (descriptionRef?.current?.clientHeight ?? 0) + (descriptionRef?.current?.scrollHeight ?? 0) <= (descriptionRef?.current?.clientHeight ?? 0) ) { setIsOverflow(false); } } - }, [content]); + }, []); - if (!content) { - return null; + if (isExpanded) { + return ( + <> + +

{children}

+
+ {isOverflow && ( + + {i18n.READ_LESS} + + )} + + ); } return ( <> - {isExpanded ? ( - -

{content}

-
- ) : isOverflow == null || isOverflow === true ? ( + {isOverflow == null || isOverflow === true ? ( - {content} + {children} ) : ( - {content} + children )} {isOverflow && ( - {isExpanded ? i18n.READ_LESS : i18n.READ_MORE} + {i18n.READ_MORE} )} diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx index c1078e1ba77e..f400887f4392 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx @@ -37,6 +37,7 @@ const FlexGroupFullHeight = styled(EuiFlexGroup)` const VerticalOverflowContainer = styled.div((props: { maxHeight: number }) => ({ 'max-height': `${props.maxHeight}px`, 'overflow-y': 'hidden', + 'word-break': 'break-word', })); const VerticalOverflowContent = styled.div((props: { maxHeight: number }) => ({ diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx index 216282b72920..479b32c2d642 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx @@ -206,11 +206,12 @@ const TimelineDescriptionComponent: React.FC = ({ timelineId const description = useDeepEqualSelector( (state) => (getTimeline(state, timelineId) ?? timelineDefaults).description ); - return ( {description.length ? ( - + + {description} + ) : ( commonI18n.DESCRIPTION )} diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx index d1d5bffc6bd0..fff2d4559c8d 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx @@ -113,7 +113,7 @@ export const ExpandableEvent = React.memo( {i18n.MESSAGE} - + {message}