[Security Solution] Fixes the Read Less
button rendering below the fold (#96524)
## [Security Solution] Fixes the `Read Less` button rendering below the fold Fixes issue <https://github.com/elastic/kibana/issues/95295> where the `Read Less` button in the Event Details flyout is rendered below the fold when an event's `message` field is too large, per the `Before` and `After` screenshots below: ### Before ![before](https://user-images.githubusercontent.com/4459398/113962310-aa463e80-97e4-11eb-93f9-f4a90bd250f6.png) _Before: The `Read Less` button is not visible in the `Event details` flyout above_ ### After ![after](https://user-images.githubusercontent.com/4459398/113962433-e9748f80-97e4-11eb-8f46-835eb12ea09d.png) _After: The `Read Less` button is visible in the `Event details` flyout above_ In the _After_ screenshot above, the long `message` is rendered in a vertically scrollable view that occupies ~ one third of the vertical height of the viewport. The `Read Less` button is visible below the message. ### Desk Testing Desk tested on a 16" MBP, and at larger desktop resolutions in: - Chrome `89.0.4389.114` - Firefox `87.0` - Safari `14.0.3`
This commit is contained in:
parent
4af344a9b0
commit
e871e84365
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* 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 { mount } from 'enzyme';
|
||||
import { repeat } from 'lodash/fp';
|
||||
import React from 'react';
|
||||
|
||||
import { LineClamp } from '.';
|
||||
|
||||
describe('LineClamp', () => {
|
||||
const message = repeat(1000, 'abcdefghij '); // 10 characters, with a trailing space
|
||||
|
||||
describe('no overflow', () => {
|
||||
test('it does NOT render the expanded line clamp when isOverflow is falsy', () => {
|
||||
const wrapper = mount(<LineClamp content={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(<LineClamp content={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(<LineClamp content={message} />);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="default-line-clamp"]').first().text()).toBe(message);
|
||||
});
|
||||
|
||||
test('it does NOT render the `Read More` button when isOverflow is falsy', () => {
|
||||
const wrapper = mount(<LineClamp content={message} />);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="summary-view-readmore"]').exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('overflow', () => {
|
||||
const clientHeight = 400;
|
||||
const scrollHeight = clientHeight + 100; // scrollHeight is > clientHeight
|
||||
|
||||
beforeAll(() => {
|
||||
Object.defineProperty(HTMLElement.prototype, 'clientHeight', {
|
||||
configurable: true,
|
||||
value: clientHeight,
|
||||
});
|
||||
|
||||
Object.defineProperty(HTMLElement.prototype, 'scrollHeight', {
|
||||
configurable: true,
|
||||
value: scrollHeight,
|
||||
});
|
||||
});
|
||||
|
||||
test('it does NOT render the expanded line clamp by default when isOverflow is true', () => {
|
||||
const wrapper = mount(<LineClamp content={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(<LineClamp content={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(<LineClamp content={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(<LineClamp content={message} />);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="summary-view-readmore"]').first().text()).toBe(
|
||||
'Read More'
|
||||
);
|
||||
});
|
||||
|
||||
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} />);
|
||||
|
||||
wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click');
|
||||
wrapper.update();
|
||||
|
||||
expect(wrapper.find('[data-test-subj="summary-view-readmore"]').first().text()).toBe(
|
||||
'Read Less'
|
||||
);
|
||||
});
|
||||
|
||||
test('it renders the expanded content after the user clicks the `Read More` button when isOverflow is true', () => {
|
||||
const wrapper = mount(<LineClamp content={message} />);
|
||||
|
||||
wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click');
|
||||
wrapper.update();
|
||||
|
||||
expect(wrapper.find('[data-test-subj="expanded-line-clamp"]').first().text()).toBe(message);
|
||||
});
|
||||
});
|
||||
|
||||
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} />);
|
||||
|
||||
wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click');
|
||||
wrapper.update();
|
||||
|
||||
expect(wrapper.find('[data-test-subj="expanded-line-clamp"]').first()).toHaveStyleRule(
|
||||
'max-height',
|
||||
'33vh'
|
||||
);
|
||||
});
|
||||
|
||||
test('it automatically vertically scrolls the content when isOverflow is true', () => {
|
||||
const wrapper = mount(<LineClamp content={message} />);
|
||||
|
||||
wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click');
|
||||
wrapper.update();
|
||||
|
||||
expect(wrapper.find('[data-test-subj="expanded-line-clamp"]').first()).toHaveStyleRule(
|
||||
'overflow-y',
|
||||
'auto'
|
||||
);
|
||||
});
|
||||
|
||||
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} />);
|
||||
|
||||
wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click');
|
||||
wrapper.update();
|
||||
|
||||
expect(wrapper.find('[data-test-subj="styled-line-clamp"]').exists()).toBe(false);
|
||||
});
|
||||
|
||||
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} />);
|
||||
|
||||
wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click');
|
||||
wrapper.update();
|
||||
|
||||
expect(wrapper.find('[data-test-subj="default-line-clamp"]').exists()).toBe(false);
|
||||
});
|
||||
|
||||
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} />);
|
||||
|
||||
wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click');
|
||||
wrapper.update(); // 1st toggle
|
||||
|
||||
wrapper.find('[data-test-subj="summary-view-readmore"]').first().simulate('click');
|
||||
wrapper.update(); // 2nd toggle
|
||||
|
||||
expect(wrapper.find('[data-test-subj="summary-view-readmore"]').first().text()).toBe(
|
||||
'Read More' // after the 2nd toggle, the button once-again says `Read More`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -11,7 +11,7 @@ import styled from 'styled-components';
|
|||
import * as i18n from './translations';
|
||||
|
||||
const LINE_CLAMP = 3;
|
||||
const LINE_CLAMP_HEIGHT = 4.5;
|
||||
const LINE_CLAMP_HEIGHT = 5.5;
|
||||
|
||||
const StyledLineClamp = styled.div`
|
||||
display: -webkit-box;
|
||||
|
@ -28,6 +28,13 @@ const ReadMore = styled(EuiButtonEmpty)`
|
|||
}
|
||||
`;
|
||||
|
||||
const ExpandedContent = styled.div`
|
||||
max-height: 33vh;
|
||||
overflow-wrap: break-word;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
`;
|
||||
|
||||
const LineClampComponent: React.FC<{ content?: string | null }> = ({ content }) => {
|
||||
const [isOverflow, setIsOverflow] = useState<boolean | null>(null);
|
||||
const [isExpanded, setIsExpanded] = useState<boolean | null>(null);
|
||||
|
@ -60,11 +67,15 @@ const LineClampComponent: React.FC<{ content?: string | null }> = ({ content })
|
|||
return (
|
||||
<>
|
||||
{isExpanded ? (
|
||||
<p>{content}</p>
|
||||
<ExpandedContent data-test-subj="expanded-line-clamp">
|
||||
<p>{content}</p>
|
||||
</ExpandedContent>
|
||||
) : isOverflow == null || isOverflow === true ? (
|
||||
<StyledLineClamp ref={descriptionRef}>{content}</StyledLineClamp>
|
||||
<StyledLineClamp data-test-subj="styled-line-clamp" ref={descriptionRef}>
|
||||
{content}
|
||||
</StyledLineClamp>
|
||||
) : (
|
||||
<EuiText>{content}</EuiText>
|
||||
<EuiText data-test-subj="default-line-clamp">{content}</EuiText>
|
||||
)}
|
||||
{isOverflow && (
|
||||
<ReadMore onClick={toggleReadMore} size="s" data-test-subj="summary-view-readmore">
|
||||
|
|
Loading…
Reference in a new issue