[Security Solution][Lists] - Update exception item viewer overflow (#125145)

### Summary

Addresses #119012

- updates exception item viewer UI
This commit is contained in:
Yara Tercero 2022-02-09 16:02:25 -08:00 committed by GitHub
parent bad98b6892
commit dba7207787
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 209 additions and 116 deletions

View file

@ -2,6 +2,6 @@
"list_id": "simple_list",
"tags": ["user added string for a tag", "malware"],
"type": "detection",
"description": "This is a sample endpoint type exception",
"name": "Sample Endpoint Exception List"
"description": "This is a sample detection type exception",
"name": "Sample Detection Exception List"
}

View file

@ -11,7 +11,6 @@ import {
EuiDescriptionList,
EuiButtonEmpty,
EuiDescriptionListTitle,
EuiDescriptionListDescription,
EuiToolTip,
} from '@elastic/eui';
import React, { useMemo, Fragment } from 'react';
@ -92,7 +91,11 @@ const ExceptionDetailsComponent = ({
<MyExceptionDetails grow={2}>
<EuiFlexGroup direction="column" alignItems="flexStart">
<EuiFlexItem grow={1} className="eventFiltersDescriptionList">
<EuiDescriptionList compressed type="column" data-test-subj="exceptionsViewerItemDetails">
<EuiDescriptionList
compressed
type="responsiveColumn"
data-test-subj="exceptionsViewerItemDetails"
>
{descriptionListItems.map((item) => (
<Fragment key={`${item.title}`}>
<EuiToolTip content={item.title} anchorClassName="eventFiltersDescriptionListTitle">
@ -100,14 +103,7 @@ const ExceptionDetailsComponent = ({
{item.title}
</EuiDescriptionListTitle>
</EuiToolTip>
<EuiToolTip
content={item.description}
anchorClassName="eventFiltersDescriptionListDescription"
>
<EuiDescriptionListDescription className="eui-textBreakWord eui-textTruncate eui-fullWidth">
{item.description}
</EuiDescriptionListDescription>
</EuiToolTip>
{item.description}
</Fragment>
))}
</EuiDescriptionList>

View file

@ -150,8 +150,7 @@ const ExceptionEntriesComponent = ({
},
},
],
// eslint-disable-next-line react-hooks/exhaustive-deps
[entries]
[]
);
return (

View file

@ -8,7 +8,7 @@
import moment from 'moment-timezone';
import { getFormattedEntries, formatEntry, getDescriptionListContent } from './helpers';
import { FormattedEntry, DescriptionListItem } from '../types';
import { FormattedEntry } from '../types';
import { getExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/exception_list_item_schema.mock';
import { getEntriesArrayMock } from '../../../../../../lists/common/schemas/types/entries.mock';
import { getEntryMatchMock } from '../../../../../../lists/common/schemas/types/entry_match.mock';
@ -157,103 +157,171 @@ describe('Exception viewer helpers', () => {
const payload = getExceptionListItemSchemaMock({ os_types: ['linux'] });
payload.description = '';
const result = getDescriptionListContent(payload);
const expected: DescriptionListItem[] = [
{
description: 'Linux',
title: 'OS',
},
{
description: 'April 20th 2020 @ 15:25:31',
title: 'Date created',
},
{
description: 'some user',
title: 'Created by',
},
];
const os = result.find(({ title }) => title === 'OS');
expect(result).toEqual(expected);
expect(os).toMatchInlineSnapshot(`
Object {
"description": <EuiToolTip
anchorClassName="eventFiltersDescriptionListDescription"
content="Linux"
delay="regular"
display="inlineBlock"
position="top"
>
<EuiDescriptionListDescription
className="eui-fullWidth"
>
Linux
</EuiDescriptionListDescription>
</EuiToolTip>,
"title": "OS",
}
`);
});
test('it returns formatted description list with a description if one specified', () => {
const payload = getExceptionListItemSchemaMock({ os_types: ['linux'] });
payload.description = 'Im a description';
const result = getDescriptionListContent(payload);
const expected: DescriptionListItem[] = [
{
description: 'Linux',
title: 'OS',
},
{
description: 'April 20th 2020 @ 15:25:31',
title: 'Date created',
},
{
description: 'some user',
title: 'Created by',
},
{
description: 'Im a description',
title: 'Description',
},
];
const description = result.find(({ title }) => title === 'Description');
expect(result).toEqual(expected);
expect(description).toMatchInlineSnapshot(`
Object {
"description": <EuiToolTip
anchorClassName="eventFiltersDescriptionListDescription"
content="Im a description"
delay="regular"
display="inlineBlock"
position="top"
>
<EuiDescriptionListDescription
className="eui-fullWidth"
>
Im a description
</EuiDescriptionListDescription>
</EuiToolTip>,
"title": "Description",
}
`);
});
test('it returns scrolling element when description is longer than 75 charachters', () => {
const payload = getExceptionListItemSchemaMock({ os_types: ['linux'] });
payload.description =
'Puppy kitty ipsum dolor sit good dog foot stick canary. Teeth Mittens grooming vaccine walk swimming nest good boy furry tongue heel furry treats fish. Cage run fast kitten dinnertime ball run foot park fleas throw house train licks stick dinnertime window. Yawn litter fish yawn toy pet gate throw Buddy kitty wag tail ball groom crate ferret heel wet nose Rover toys pet supplies. Bird Food treats tongue lick teeth ferret litter box slobbery litter box crate bird small animals yawn small animals shake slobber gimme five toys polydactyl meow. ';
const result = getDescriptionListContent(payload);
const description = result.find(({ title }) => title === 'Description');
expect(description).toMatchInlineSnapshot(`
Object {
"description": <EuiDescriptionListDescription
style={
Object {
"height": 150,
"overflowY": "hidden",
}
}
>
<EuiText
aria-label=""
className="eui-yScrollWithShadows"
role="region"
size="s"
tabIndex={0}
>
Puppy kitty ipsum dolor sit good dog foot stick canary. Teeth Mittens grooming vaccine walk swimming nest good boy furry tongue heel furry treats fish. Cage run fast kitten dinnertime ball run foot park fleas throw house train licks stick dinnertime window. Yawn litter fish yawn toy pet gate throw Buddy kitty wag tail ball groom crate ferret heel wet nose Rover toys pet supplies. Bird Food treats tongue lick teeth ferret litter box slobbery litter box crate bird small animals yawn small animals shake slobber gimme five toys polydactyl meow.
</EuiText>
</EuiDescriptionListDescription>,
"title": "Description",
}
`);
});
test('it returns just user and date created if no other fields specified', () => {
const payload = getExceptionListItemSchemaMock({ os_types: ['linux'] });
const payload = getExceptionListItemSchemaMock();
payload.description = '';
const result = getDescriptionListContent(payload);
const expected: DescriptionListItem[] = [
{
description: 'Linux',
title: 'OS',
},
{
description: 'April 20th 2020 @ 15:25:31',
title: 'Date created',
},
{
description: 'some user',
title: 'Created by',
},
];
expect(result).toEqual(expected);
expect(result).toMatchInlineSnapshot(`
Array [
Object {
"description": <EuiToolTip
anchorClassName="eventFiltersDescriptionListDescription"
content="April 20th 2020 @ 15:25:31"
delay="regular"
display="inlineBlock"
position="top"
>
<EuiDescriptionListDescription
className="eui-fullWidth"
>
April 20th 2020 @ 15:25:31
</EuiDescriptionListDescription>
</EuiToolTip>,
"title": "Date created",
},
Object {
"description": <EuiToolTip
anchorClassName="eventFiltersDescriptionListDescription"
content="some user"
delay="regular"
display="inlineBlock"
position="top"
>
<EuiDescriptionListDescription
className="eui-fullWidth"
>
some user
</EuiDescriptionListDescription>
</EuiToolTip>,
"title": "Created by",
},
]
`);
});
test('it returns Modified By/On info. when `includeModified` is true', () => {
test('it returns Modified By/On info when `includeModified` is true', () => {
const result = getDescriptionListContent(
getExceptionListItemSchemaMock({ os_types: ['linux'] }),
true
);
expect(result).toEqual([
{
description: 'Linux',
title: 'OS',
},
{
description: 'April 20th 2020 @ 15:25:31',
title: 'Date created',
},
{
description: 'some user',
title: 'Created by',
},
{
description: 'April 20th 2020 @ 15:25:31',
title: 'Date modified',
},
{
description: 'some user',
title: 'Modified by',
},
{
description: 'some description',
title: 'Description',
},
]);
const dateModified = result.find(({ title }) => title === 'Date modified');
const modifiedBy = result.find(({ title }) => title === 'Modified by');
expect(modifiedBy).toMatchInlineSnapshot(`
Object {
"description": <EuiToolTip
anchorClassName="eventFiltersDescriptionListDescription"
content="some user"
delay="regular"
display="inlineBlock"
position="top"
>
<EuiDescriptionListDescription
className="eui-fullWidth"
>
some user
</EuiDescriptionListDescription>
</EuiToolTip>,
"title": "Modified by",
}
`);
expect(dateModified).toMatchInlineSnapshot(`
Object {
"description": <EuiToolTip
anchorClassName="eventFiltersDescriptionListDescription"
content="April 20th 2020 @ 15:25:31"
delay="regular"
display="inlineBlock"
position="top"
>
<EuiDescriptionListDescription
className="eui-fullWidth"
>
April 20th 2020 @ 15:25:31
</EuiDescriptionListDescription>
</EuiToolTip>,
"title": "Date modified",
}
`);
});
test('it returns Name when `includeName` is true', () => {
@ -262,28 +330,25 @@ describe('Exception viewer helpers', () => {
false,
true
);
expect(result).toEqual([
{
description: 'some name',
title: 'Name',
},
{
description: 'Linux',
title: 'OS',
},
{
description: 'April 20th 2020 @ 15:25:31',
title: 'Date created',
},
{
description: 'some user',
title: 'Created by',
},
{
description: 'some description',
title: 'Description',
},
]);
const name = result.find(({ title }) => title === 'Name');
expect(name).toMatchInlineSnapshot(`
Object {
"description": <EuiToolTip
anchorClassName="eventFiltersDescriptionListDescription"
content="some name"
delay="regular"
display="inlineBlock"
position="top"
>
<EuiDescriptionListDescription
className="eui-fullWidth"
>
some name
</EuiDescriptionListDescription>
</EuiToolTip>,
"title": "Name",
}
`);
});
});
});

View file

@ -14,6 +14,8 @@ import {
BuilderEntry,
} from '@kbn/securitysolution-list-utils';
import React from 'react';
import { EuiDescriptionListDescription, EuiText, EuiToolTip } from '@elastic/eui';
import { formatOperatingSystems } from '../helpers';
import type { FormattedEntry, DescriptionListItem } from '../types';
import * as i18n from '../translations';
@ -125,7 +127,38 @@ export const getDescriptionListContent = (
return details.reduce<DescriptionListItem[]>((acc, { value, title }) => {
if (value != null && value.trim() !== '') {
return [...acc, { title, description: value }];
const valueElement = (
<EuiToolTip content={value} anchorClassName="eventFiltersDescriptionListDescription">
<EuiDescriptionListDescription className="eui-fullWidth">
{value}
</EuiDescriptionListDescription>
</EuiToolTip>
);
if (title === i18n.DESCRIPTION) {
return [
...acc,
{
title,
description:
value.length > 75 ? (
<EuiDescriptionListDescription style={{ height: 150, overflowY: 'hidden' }}>
<EuiText
tabIndex={0}
role="region"
aria-label=""
className="eui-yScrollWithShadows"
size="s"
>
{value}
</EuiText>
</EuiDescriptionListDescription>
) : (
valueElement
),
},
];
}
return [...acc, { title, description: valueElement }];
} else {
return acc;
}