diff --git a/x-pack/plugins/security_solution/public/common/components/and_or_badge/__examples__/index.stories.tsx b/x-pack/plugins/security_solution/public/common/components/and_or_badge/__examples__/index.stories.tsx
index f939cf81d1bd3..7465d3ca1e63a 100644
--- a/x-pack/plugins/security_solution/public/common/components/and_or_badge/__examples__/index.stories.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/and_or_badge/__examples__/index.stories.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { storiesOf } from '@storybook/react';
-import React from 'react';
+import React, { ReactNode } from 'react';
import { ThemeProvider } from 'styled-components';
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
import { EuiFlexItem, EuiFlexGroup } from '@elastic/eui';
@@ -14,26 +14,21 @@ import { AndOrBadge } from '..';
const sampleText =
'Doggo ipsum i am bekom fat snoot wow such tempt waggy wags floofs, ruff heckin good boys and girls mlem. Ruff heckin good boys and girls mlem stop it fren borkf borking doggo very hand that feed shibe, you are doing me the shock big ol heck smol borking doggo with a long snoot for pats heckin good boys. You are doing me the shock smol borking doggo with a long snoot for pats wow very biscit, length boy. Doggo ipsum i am bekom fat snoot wow such tempt waggy wags floofs, ruff heckin good boys and girls mlem. Ruff heckin good boys and girls mlem stop it fren borkf borking doggo very hand that feed shibe, you are doing me the shock big ol heck smol borking doggo with a long snoot for pats heckin good boys.';
+const withTheme = (storyFn: () => ReactNode) => (
+ ({ eui: euiLightVars, darkMode: true })}>{storyFn()}
+);
+
storiesOf('components/AndOrBadge', module)
- .add('and', () => (
- ({ eui: euiLightVars, darkMode: true })}>
-
-
- ))
- .add('or', () => (
- ({ eui: euiLightVars, darkMode: true })}>
-
-
- ))
+ .addDecorator(withTheme)
+ .add('and', () => )
+ .add('or', () => )
.add('antennas', () => (
- ({ eui: euiLightVars, darkMode: true })}>
-
-
-
-
-
- {sampleText}
-
-
-
+
+
+
+
+
+ {sampleText}
+
+
));
diff --git a/x-pack/plugins/security_solution/public/common/components/and_or_badge/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/and_or_badge/index.test.tsx
index ed918a59a514a..f2c7d6884bae3 100644
--- a/x-pack/plugins/security_solution/public/common/components/and_or_badge/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/and_or_badge/index.test.tsx
@@ -20,8 +20,20 @@ describe('AndOrBadge', () => {
);
expect(wrapper.find('[data-test-subj="and-or-badge"]').at(0).text()).toEqual('AND');
- expect(wrapper.find('EuiFlexItem[data-test-subj="andOrBadgeBarTop"]')).toHaveLength(1);
- expect(wrapper.find('EuiFlexItem[data-test-subj="andOrBadgeBarBottom"]')).toHaveLength(1);
+ expect(wrapper.find('[data-test-subj="andOrBadgeBarTop"]').exists()).toBeTruthy();
+ expect(wrapper.find('[data-test-subj="andOrBadgeBarBottom"]').exists()).toBeTruthy();
+ });
+
+ test('it does not render top and bottom antenna bars when "includeAntennas" is false', () => {
+ const wrapper = mount(
+ ({ eui: euiLightVars, darkMode: false })}>
+
+
+ );
+
+ expect(wrapper.find('[data-test-subj="and-or-badge"]').at(0).text()).toEqual('OR');
+ expect(wrapper.find('[data-test-subj="andOrBadgeBarTop"]').exists()).toBeFalsy();
+ expect(wrapper.find('[data-test-subj="andOrBadgeBarBottom"]').exists()).toBeFalsy();
});
test('it renders "and" when "type" is "and"', () => {
@@ -32,7 +44,6 @@ describe('AndOrBadge', () => {
);
expect(wrapper.find('[data-test-subj="and-or-badge"]').at(0).text()).toEqual('AND');
- expect(wrapper.find('EuiFlexItem[data-test-subj="and-or-badge-bar"]')).toHaveLength(0);
});
test('it renders "or" when "type" is "or"', () => {
@@ -43,6 +54,5 @@ describe('AndOrBadge', () => {
);
expect(wrapper.find('[data-test-subj="and-or-badge"]').at(0).text()).toEqual('OR');
- expect(wrapper.find('EuiFlexItem[data-test-subj="and-or-badge-bar"]')).toHaveLength(0);
});
});
diff --git a/x-pack/plugins/security_solution/public/common/components/and_or_badge/index.tsx b/x-pack/plugins/security_solution/public/common/components/and_or_badge/index.tsx
index ba3f880d9757e..e427e57a2c616 100644
--- a/x-pack/plugins/security_solution/public/common/components/and_or_badge/index.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/and_or_badge/index.tsx
@@ -3,70 +3,10 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
-
-import { EuiFlexGroup, EuiBadge, EuiFlexItem } from '@elastic/eui';
import React from 'react';
-import styled, { css } from 'styled-components';
-
-import * as i18n from './translations';
-
-const AndOrBadgeAntenna = styled(EuiFlexItem)`
- ${({ theme }) => css`
- background: ${theme.eui.euiColorLightShade};
- position: relative;
- width: 2px;
- &:after {
- background: ${theme.eui.euiColorLightShade};
- content: '';
- height: 8px;
- right: -4px;
- position: absolute;
- width: 9px;
- clip-path: circle();
- }
- &.topAndOrBadgeAntenna {
- &:after {
- top: -1px;
- }
- }
- &.bottomAndOrBadgeAntenna {
- &:after {
- bottom: -1px;
- }
- }
- &.euiFlexItem {
- margin: 0 12px 0 0;
- }
- `}
-`;
-
-const EuiFlexItemWrapper = styled(EuiFlexItem)`
- &.euiFlexItem {
- margin: 0 12px 0 0;
- }
-`;
-const RoundedBadge = (styled(EuiBadge)`
- align-items: center;
- border-radius: 100%;
- display: inline-flex;
- font-size: 9px;
- height: 34px;
- justify-content: center;
- margin: 0 5px 0 5px;
- padding: 7px 6px 4px 6px;
- user-select: none;
- width: 34px;
- .euiBadge__content {
- position: relative;
- top: -1px;
- }
- .euiBadge__text {
- text-overflow: clip;
- }
-` as unknown) as typeof EuiBadge;
-
-RoundedBadge.displayName = 'RoundedBadge';
+import { RoundedBadge } from './rounded_badge';
+import { RoundedBadgeAntenna } from './rounded_badge_antenna';
export type AndOr = 'and' | 'or';
@@ -74,34 +14,7 @@ export type AndOr = 'and' | 'or';
// Ref: https://github.com/elastic/eui/issues/1655
export const AndOrBadge = React.memo<{ type: AndOr; includeAntennas?: boolean }>(
({ type, includeAntennas = false }) => {
- const getBadge = () => (
-
- {type === 'and' ? i18n.AND : i18n.OR}
-
- );
-
- const getBadgeWithAntennas = () => (
-
-
- {getBadge()}
-
-
- );
-
- return includeAntennas ? getBadgeWithAntennas() : getBadge();
+ return includeAntennas ? : ;
}
);
diff --git a/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge.test.tsx b/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge.test.tsx
new file mode 100644
index 0000000000000..14d9627d48ad7
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge.test.tsx
@@ -0,0 +1,34 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { ThemeProvider } from 'styled-components';
+import { mount } from 'enzyme';
+import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
+
+import { RoundedBadge } from './rounded_badge';
+
+describe('RoundedBadge', () => {
+ test('it renders "and" when "type" is "and"', () => {
+ const wrapper = mount(
+ ({ eui: euiLightVars, darkMode: false })}>
+
+
+ );
+
+ expect(wrapper.find('[data-test-subj="and-or-badge"]').at(0).text()).toEqual('AND');
+ });
+
+ test('it renders "or" when "type" is "or"', () => {
+ const wrapper = mount(
+ ({ eui: euiLightVars, darkMode: false })}>
+
+
+ );
+
+ expect(wrapper.find('[data-test-subj="and-or-badge"]').at(0).text()).toEqual('OR');
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge.tsx b/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge.tsx
new file mode 100644
index 0000000000000..1a03e8c73f252
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge.tsx
@@ -0,0 +1,42 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { EuiBadge } from '@elastic/eui';
+import React from 'react';
+import styled from 'styled-components';
+
+import * as i18n from './translations';
+import { AndOr } from '.';
+
+const RoundBadge = (styled(EuiBadge)`
+ align-items: center;
+ border-radius: 100%;
+ display: inline-flex;
+ font-size: 9px;
+ height: 34px;
+ justify-content: center;
+ margin: 0 5px 0 5px;
+ padding: 7px 6px 4px 6px;
+ user-select: none;
+ width: 34px;
+ .euiBadge__content {
+ position: relative;
+ top: -1px;
+ }
+ .euiBadge__text {
+ text-overflow: clip;
+ }
+` as unknown) as typeof EuiBadge;
+
+RoundBadge.displayName = 'RoundBadge';
+
+export const RoundedBadge: React.FC<{ type: AndOr }> = ({ type }) => (
+
+ {type === 'and' ? i18n.AND : i18n.OR}
+
+);
+
+RoundedBadge.displayName = 'RoundedBadge';
diff --git a/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge_antenna.test.tsx b/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge_antenna.test.tsx
new file mode 100644
index 0000000000000..e6362f8798fa6
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge_antenna.test.tsx
@@ -0,0 +1,46 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { ThemeProvider } from 'styled-components';
+import { mount } from 'enzyme';
+import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
+
+import { RoundedBadgeAntenna } from './rounded_badge_antenna';
+
+describe('RoundedBadgeAntenna', () => {
+ test('it renders top and bottom antenna bars', () => {
+ const wrapper = mount(
+ ({ eui: euiLightVars, darkMode: false })}>
+
+
+ );
+
+ expect(wrapper.find('[data-test-subj="and-or-badge"]').at(0).text()).toEqual('AND');
+ expect(wrapper.find('[data-test-subj="andOrBadgeBarTop"]').exists()).toBeTruthy();
+ expect(wrapper.find('[data-test-subj="andOrBadgeBarBottom"]').exists()).toBeTruthy();
+ });
+
+ test('it renders "and" when "type" is "and"', () => {
+ const wrapper = mount(
+ ({ eui: euiLightVars, darkMode: false })}>
+
+
+ );
+
+ expect(wrapper.find('[data-test-subj="and-or-badge"]').at(0).text()).toEqual('AND');
+ });
+
+ test('it renders "or" when "type" is "or"', () => {
+ const wrapper = mount(
+ ({ eui: euiLightVars, darkMode: false })}>
+
+
+ );
+
+ expect(wrapper.find('[data-test-subj="and-or-badge"]').at(0).text()).toEqual('OR');
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge_antenna.tsx b/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge_antenna.tsx
new file mode 100644
index 0000000000000..1076d8b41b955
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge_antenna.tsx
@@ -0,0 +1,62 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
+import React from 'react';
+import styled, { css } from 'styled-components';
+
+import { RoundedBadge } from './rounded_badge';
+import { AndOr } from '.';
+
+const antennaStyles = css`
+ background: ${({ theme }) => theme.eui.euiColorLightShade};
+ position: relative;
+ width: 2px;
+ margin: 0 12px 0 0;
+ &:after {
+ background: ${({ theme }) => theme.eui.euiColorLightShade};
+ content: '';
+ height: 8px;
+ right: -4px;
+ position: absolute;
+ width: 10px;
+ clip-path: circle();
+ }
+`;
+
+const TopAntenna = styled(EuiFlexItem)`
+ ${antennaStyles}
+ &:after {
+ top: 0;
+ }
+`;
+const BottomAntenna = styled(EuiFlexItem)`
+ ${antennaStyles}
+ &:after {
+ bottom: 0;
+ }
+`;
+
+const EuiFlexItemWrapper = styled(EuiFlexItem)`
+ margin: 0 12px 0 0;
+`;
+
+export const RoundedBadgeAntenna: React.FC<{ type: AndOr }> = ({ type }) => (
+
+
+
+
+
+
+
+);
+
+RoundedBadgeAntenna.displayName = 'RoundedBadgeAntenna';
diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/__examples__/index.stories.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/__examples__/index.stories.tsx
index b6620ed103bc8..f2dc9f7e69e2d 100644
--- a/x-pack/plugins/security_solution/public/common/components/exceptions/__examples__/index.stories.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/exceptions/__examples__/index.stories.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { storiesOf } from '@storybook/react';
-import React from 'react';
+import React, { ReactNode } from 'react';
import { ThemeProvider } from 'styled-components';
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
@@ -12,7 +12,12 @@ import { ExceptionItem } from '../viewer';
import { Operator } from '../types';
import { getExceptionItemMock } from '../mocks';
+const withTheme = (storyFn: () => ReactNode) => (
+ ({ eui: euiLightVars, darkMode: true })}>{storyFn()}
+);
+
storiesOf('components/exceptions', module)
+ .addDecorator(withTheme)
.add('ExceptionItem/with os', () => {
const payload = getExceptionItemMock();
payload.description = '';
@@ -27,14 +32,12 @@ storiesOf('components/exceptions', module)
];
return (
- ({ eui: euiLightVars, darkMode: false })}>
- {}}
- handleEdit={() => {}}
- />
-
+ {}}
+ handleEdit={() => {}}
+ />
);
})
.add('ExceptionItem/with description', () => {
@@ -51,14 +54,12 @@ storiesOf('components/exceptions', module)
];
return (
- ({ eui: euiLightVars, darkMode: false })}>
- {}}
- handleEdit={() => {}}
- />
-
+ {}}
+ handleEdit={() => {}}
+ />
);
})
.add('ExceptionItem/with comments', () => {
@@ -75,14 +76,12 @@ storiesOf('components/exceptions', module)
];
return (
- ({ eui: euiLightVars, darkMode: false })}>
- {}}
- handleEdit={() => {}}
- />
-
+ {}}
+ handleEdit={() => {}}
+ />
);
})
.add('ExceptionItem/with nested entries', () => {
@@ -92,27 +91,23 @@ storiesOf('components/exceptions', module)
payload.comments = [];
return (
- ({ eui: euiLightVars, darkMode: false })}>
- {}}
- handleEdit={() => {}}
- />
-
+ {}}
+ handleEdit={() => {}}
+ />
);
})
.add('ExceptionItem/with everything', () => {
const payload = getExceptionItemMock();
return (
- ({ eui: euiLightVars, darkMode: false })}>
- {}}
- handleEdit={() => {}}
- />
-
+ {}}
+ handleEdit={() => {}}
+ />
);
});
diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx
index 223eabb0ea4ee..d86a84996a34f 100644
--- a/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx
@@ -10,7 +10,7 @@ import moment from 'moment-timezone';
import {
getOperatorType,
getExceptionOperatorSelect,
- determineIfIsNested,
+ isEntryNested,
getFormattedEntries,
formatEntry,
getOperatingSystems,
@@ -159,21 +159,21 @@ describe('Exception helpers', () => {
});
});
- describe('#determineIfIsNested', () => {
+ describe('#isEntryNested', () => {
test('it returns true if type NestedExceptionEntry', () => {
const payload: NestedExceptionEntry = {
field: 'actingProcess.file.signer',
type: 'nested',
entries: [],
};
- const result = determineIfIsNested(payload);
+ const result = isEntryNested(payload);
expect(result).toBeTruthy();
});
test('it returns false if NOT type NestedExceptionEntry', () => {
const payload = getExceptionItemEntryMock();
- const result = determineIfIsNested(payload);
+ const result = isEntryNested(payload);
expect(result).toBeFalsy();
});
diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.tsx
index bd22de636bf6c..155c8a3e2926c 100644
--- a/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.tsx
@@ -56,7 +56,7 @@ export const getExceptionOperatorSelect = (entry: ExceptionEntry): OperatorOptio
return foundOperator ?? isOperator;
};
-export const determineIfIsNested = (
+export const isEntryNested = (
tbd: ExceptionEntry | NestedExceptionEntry
): tbd is NestedExceptionEntry => {
if (tbd.type === 'nested') {
@@ -75,7 +75,7 @@ export const getFormattedEntries = (
entries: Array
): FormattedEntry[] => {
const formattedEntries = entries.map((entry) => {
- if (determineIfIsNested(entry)) {
+ if (isEntryNested(entry)) {
const parent = { fieldName: entry.field, operator: null, value: null, isNested: false };
return entry.entries.reduce(
(acc, nestedEntry) => {
diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_details.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_details.tsx
index 8745e80a21548..5a9fa5c5cc1d5 100644
--- a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_details.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_details.tsx
@@ -4,10 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { EuiFlexItem, EuiFlexGroup, EuiDescriptionList, EuiButtonEmpty } from '@elastic/eui';
-import React, { useMemo } from 'react';
+import {
+ EuiFlexItem,
+ EuiFlexGroup,
+ EuiDescriptionList,
+ EuiButtonEmpty,
+ EuiDescriptionListTitle,
+ EuiDescriptionListDescription,
+} from '@elastic/eui';
+import React, { useMemo, Fragment } from 'react';
import styled, { css } from 'styled-components';
-import { transparentize } from 'polished';
import { ExceptionListItemSchema } from '../types';
import { getDescriptionListContent } from '../helpers';
@@ -15,17 +21,17 @@ import * as i18n from '../translations';
const StyledExceptionDetails = styled(EuiFlexItem)`
${({ theme }) => css`
- background-color: ${transparentize(0.95, theme.eui.euiColorPrimary)};
+ background-color: ${theme.eui.euiColorLightestShade};
padding: ${theme.eui.euiSize};
+ `}
+`;
- .euiDescriptionList__title.listTitle--width {
- width: 40%;
- }
+const MyDescriptionListTitle = styled(EuiDescriptionListTitle)`
+ width: 40%;
+`;
- .euiDescriptionList__description.listDescription--width {
- width: 60%;
- }
- `}
+const MyDescriptionListDescription = styled(EuiDescriptionListDescription)`
+ width: 60%;
`;
const ExceptionDetailsComponent = ({
@@ -37,7 +43,9 @@ const ExceptionDetailsComponent = ({
exceptionItem: ExceptionListItemSchema;
onCommentsClick: () => void;
}): JSX.Element => {
- const descriptionList = useMemo(() => getDescriptionListContent(exceptionItem), [exceptionItem]);
+ const descriptionListItems = useMemo(() => getDescriptionListContent(exceptionItem), [
+ exceptionItem,
+ ]);
const commentsSection = useMemo((): JSX.Element => {
const { comments } = exceptionItem;
@@ -63,14 +71,14 @@ const ExceptionDetailsComponent = ({
-
+
+ {descriptionListItems.map((item) => (
+
+ {item.title}
+ {item.description}
+
+ ))}
+
{commentsSection}
diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_entries.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_entries.tsx
index fa21d61b06ebe..09d3a7d259984 100644
--- a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_entries.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_entries.tsx
@@ -134,7 +134,7 @@ const ExceptionEntriesComponent = ({
-
+