[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>
This commit is contained in:
parent
24661fe208
commit
6ee79558ab
|
@ -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<{
|
|||
<StyledEuiDescriptionList data-test-subj={`summary-view-guide`} compressed>
|
||||
<EuiDescriptionListTitle>{i18n.INVESTIGATION_GUIDE}</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription>
|
||||
<LineClamp content={maybeRule?.note} />
|
||||
<LineClamp>
|
||||
<MarkdownRenderer>{maybeRule.note}</MarkdownRenderer>
|
||||
</LineClamp>
|
||||
</EuiDescriptionListDescription>
|
||||
</StyledEuiDescriptionList>
|
||||
)}
|
||||
|
|
|
@ -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(<LineClamp content={message} />);
|
||||
const wrapper = mount(<LineClamp>{message}</LineClamp>);
|
||||
|
||||
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(<LineClamp content={message} />);
|
||||
const wrapper = mount(<LineClamp>{message}</LineClamp>);
|
||||
|
||||
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(<LineClamp content={message} />);
|
||||
test('it renders the children when isOverflow is falsy', () => {
|
||||
const TestComponent = () => <>{message}</>;
|
||||
const wrapper = mount(
|
||||
<LineClamp>
|
||||
<TestComponent />
|
||||
</LineClamp>
|
||||
);
|
||||
|
||||
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(<LineClamp content={message} />);
|
||||
const wrapper = mount(<LineClamp>{message}</LineClamp>);
|
||||
|
||||
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(<LineClamp content={message} />);
|
||||
const wrapper = mount(<LineClamp>{message}</LineClamp>);
|
||||
|
||||
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(<LineClamp content={message} />);
|
||||
const wrapper = mount(<LineClamp>{message}</LineClamp>);
|
||||
|
||||
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(<LineClamp content={message} />);
|
||||
const wrapper = mount(<LineClamp>{message}</LineClamp>);
|
||||
|
||||
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(<LineClamp content={message} />);
|
||||
const wrapper = mount(<LineClamp>{message}</LineClamp>);
|
||||
|
||||
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(<LineClamp content={message} />);
|
||||
const wrapper = mount(<LineClamp>{message}</LineClamp>);
|
||||
|
||||
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(<LineClamp content={message} />);
|
||||
const wrapper = mount(<LineClamp>{message}</LineClamp>);
|
||||
|
||||
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(<LineClamp content={message} />);
|
||||
const wrapper = mount(<LineClamp>{message}</LineClamp>);
|
||||
|
||||
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(<LineClamp content={message} />);
|
||||
const wrapper = mount(<LineClamp>{message}</LineClamp>);
|
||||
|
||||
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(<LineClamp content={message} />);
|
||||
const wrapper = mount(<LineClamp>{message}</LineClamp>);
|
||||
|
||||
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(<LineClamp content={message} />);
|
||||
const wrapper = mount(<LineClamp>{message}</LineClamp>);
|
||||
|
||||
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(<LineClamp content={message} />);
|
||||
const wrapper = mount(<LineClamp>{message}</LineClamp>);
|
||||
|
||||
wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click');
|
||||
wrapper.update(); // 1st toggle
|
||||
|
|
|
@ -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<boolean | null>(null);
|
||||
const [isExpanded, setIsExpanded] = useState<boolean | null>(null);
|
||||
const descriptionRef = useRef<HTMLDivElement>(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 (
|
||||
<>
|
||||
<ExpandedContent data-test-subj="expanded-line-clamp">
|
||||
<p>{children}</p>
|
||||
</ExpandedContent>
|
||||
{isOverflow && (
|
||||
<ReadMore onClick={toggleReadMore} size="s" data-test-subj="summary-view-readmore">
|
||||
{i18n.READ_LESS}
|
||||
</ReadMore>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isExpanded ? (
|
||||
<ExpandedContent data-test-subj="expanded-line-clamp">
|
||||
<p>{content}</p>
|
||||
</ExpandedContent>
|
||||
) : isOverflow == null || isOverflow === true ? (
|
||||
{isOverflow == null || isOverflow === true ? (
|
||||
<StyledLineClamp
|
||||
data-test-subj="styled-line-clamp"
|
||||
ref={descriptionRef}
|
||||
lineClampHeight={lineClampHeight}
|
||||
>
|
||||
{content}
|
||||
{children}
|
||||
</StyledLineClamp>
|
||||
) : (
|
||||
<EuiText data-test-subj="default-line-clamp">{content}</EuiText>
|
||||
children
|
||||
)}
|
||||
{isOverflow && (
|
||||
<ReadMore onClick={toggleReadMore} size="s" data-test-subj="summary-view-readmore">
|
||||
{isExpanded ? i18n.READ_LESS : i18n.READ_MORE}
|
||||
{i18n.READ_MORE}
|
||||
</ReadMore>
|
||||
)}
|
||||
</>
|
||||
|
|
|
@ -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 }) => ({
|
||||
|
|
|
@ -206,11 +206,12 @@ const TimelineDescriptionComponent: React.FC<FlyoutHeaderProps> = ({ timelineId
|
|||
const description = useDeepEqualSelector(
|
||||
(state) => (getTimeline(state, timelineId) ?? timelineDefaults).description
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiText size="s" data-test-subj="timeline-description">
|
||||
{description.length ? (
|
||||
<LineClamp key={description.length} content={description} lineClampHeight={4.5} />
|
||||
<LineClamp key={description.length} lineClampHeight={4.5}>
|
||||
{description}
|
||||
</LineClamp>
|
||||
) : (
|
||||
commonI18n.DESCRIPTION
|
||||
)}
|
||||
|
|
|
@ -113,7 +113,7 @@ export const ExpandableEvent = React.memo<Props>(
|
|||
<EuiDescriptionList data-test-subj="event-message" compressed>
|
||||
<EuiDescriptionListTitle>{i18n.MESSAGE}</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription>
|
||||
<LineClamp content={message} />
|
||||
<LineClamp>{message}</LineClamp>
|
||||
</EuiDescriptionListDescription>
|
||||
</EuiDescriptionList>
|
||||
<EuiSpacer size="m" />
|
||||
|
|
Loading…
Reference in a new issue