Skip to content

Commit

Permalink
[SIEM] Detection Engine Create Rule Design Review #1 (elastic#54442) (e…
Browse files Browse the repository at this point in the history
  • Loading branch information
patrykkopycinski committed Jan 13, 2020
1 parent 7465b44 commit 93093a1
Show file tree
Hide file tree
Showing 20 changed files with 588 additions and 426 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,12 @@ import {
EuiTableActionsColumnType,
EuiBasicTableColumn,
EuiBadge,
EuiHealth,
EuiIconTip,
EuiLink,
EuiTextColor,
} from '@elastic/eui';
import * as H from 'history';
import React from 'react';
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
import { getEmptyTagValue } from '../../../../components/empty_value';
import {
deleteRulesAction,
Expand All @@ -32,6 +30,7 @@ import { TableData } from '../types';
import * as i18n from '../translations';
import { PreferenceFormattedDate } from '../../../../components/formatted_date';
import { RuleSwitch } from '../components/rule_switch';
import { SeverityBadge } from '../components/severity_badge';

const getActions = (dispatch: React.Dispatch<Action>, history: H.History) => [
{
Expand Down Expand Up @@ -97,21 +96,7 @@ export const getColumns = (
{
field: 'severity',
name: i18n.COLUMN_SEVERITY,
render: (value: TableData['severity']) => (
<EuiHealth
color={
value === 'low'
? euiLightVars.euiColorVis0
: value === 'medium'
? euiLightVars.euiColorVis5
: value === 'high'
? euiLightVars.euiColorVis7
: euiLightVars.euiColorVis9
}
>
{value}
</EuiHealth>
),
render: (value: TableData['severity']) => <SeverityBadge value={value} />,
truncateText: true,
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,25 @@ const MyEuiFormRow = styled(EuiFormRow)`
}
`;

export const MyAddItemButton = styled(EuiButtonEmpty)`
margin-top: 4px;
&.euiButtonEmpty--xSmall {
font-size: 12px;
}
.euiIcon {
width: 12px;
height: 12px;
}
`;

MyAddItemButton.defaultProps = {
flush: 'left',
iconType: 'plusInCircle',
size: 'xs',
};

export const AddItem = ({
addText,
dataTestSubj,
Expand Down Expand Up @@ -160,9 +179,9 @@ export const AddItem = ({
);
})}

<EuiButtonEmpty size="xs" onClick={addItem} isDisabled={isDisabled} iconType="plusInCircle">
<MyAddItemButton onClick={addItem} isDisabled={isDisabled}>
{addText}
</EuiButtonEmpty>
</MyAddItemButton>
</>
</MyEuiFormRow>
);
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ import {
EuiLoadingSpinner,
EuiFlexGroup,
EuiFlexItem,
EuiHealth,
EuiLink,
EuiText,
EuiListGroup,
EuiButtonEmpty,
EuiSpacer,
} from '@elastic/eui';
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';

import { isEmpty } from 'lodash/fp';
import React from 'react';
Expand All @@ -27,6 +25,11 @@ import { tacticsOptions, techniquesOptions } from '../../../mitre/mitre_tactics_
import { FilterLabel } from './filter_label';
import * as i18n from './translations';
import { BuildQueryBarDescription, BuildThreatsDescription, ListItems } from './types';
import { SeverityBadge } from '../severity_badge';
import ListTreeIcon from './assets/list_tree_icon.svg';

const isNotEmptyArray = (values: string[]) =>
!isEmpty(values) && values.filter(val => !isEmpty(val)).length > 0;

const EuiBadgeWrap = styled(EuiBadge)`
.euiBadge__text {
Expand Down Expand Up @@ -97,10 +100,17 @@ const ThreatsEuiFlexGroup = styled(EuiFlexGroup)`
}
`;

const MyEuiListGroup = styled(EuiListGroup)`
padding: 0px;
.euiListGroupItem__button {
padding: 0px;
const TechniqueLinkItem = styled(EuiButtonEmpty)`
.euiIcon {
width: 8px;
height: 8px;
}
`;

const ReferenceLinkItem = styled(EuiButtonEmpty)`
.euiIcon {
width: 12px;
height: 12px;
}
`;

Expand All @@ -118,28 +128,31 @@ export const buildThreatsDescription = ({
const tactic = tacticsOptions.find(t => t.name === threat.tactic.name);
return (
<EuiFlexItem key={`${threat.tactic.name}-${index}`}>
<EuiText grow={false} size="s">
<h5>
<EuiLink href={threat.tactic.reference} target="_blank">
{tactic != null ? tactic.text : ''}
</EuiLink>
</h5>
<MyEuiListGroup
flush={false}
bordered={false}
listItems={threat.techniques.map(technique => {
const myTechnique = techniquesOptions.find(t => t.name === technique.name);
return {
label: myTechnique != null ? myTechnique.label : '',
href: technique.reference,
target: '_blank',
};
})}
/>
</EuiText>
<EuiLink href={threat.tactic.reference} target="_blank">
{tactic != null ? tactic.text : ''}
</EuiLink>
<EuiFlexGroup gutterSize="none" alignItems="flexStart" direction="column">
{threat.techniques.map(technique => {
const myTechnique = techniquesOptions.find(t => t.name === technique.name);
return (
<EuiFlexItem>
<TechniqueLinkItem
href={technique.reference}
target="_blank"
iconType={ListTreeIcon}
size="xs"
flush="left"
>
{myTechnique != null ? myTechnique.label : ''}
</TechniqueLinkItem>
</EuiFlexItem>
);
})}
</EuiFlexGroup>
</EuiFlexItem>
);
})}
<EuiSpacer />
</ThreatsEuiFlexGroup>
),
},
Expand All @@ -148,12 +161,34 @@ export const buildThreatsDescription = ({
return [];
};

export const buildUnorderedListArrayDescription = (
label: string,
field: string,
values: string[]
): ListItems[] => {
if (isNotEmptyArray(values)) {
return [
{
title: label,
description: (
<ul>
{values.map((val: string) =>
isEmpty(val) ? null : <li key={`${field}-${val}`}>{val}</li>
)}
</ul>
),
},
];
}
return [];
};

export const buildStringArrayDescription = (
label: string,
field: string,
values: string[]
): ListItems[] => {
if (!isEmpty(values) && values.filter(val => !isEmpty(val)).length > 0) {
if (isNotEmptyArray(values)) {
return [
{
title: label,
Expand All @@ -174,46 +209,34 @@ export const buildStringArrayDescription = (
return [];
};

export const buildSeverityDescription = (label: string, value: string): ListItems[] => {
return [
{
title: label,
description: (
<EuiHealth
color={
value === 'low'
? euiLightVars.euiColorVis0
: value === 'medium'
? euiLightVars.euiColorVis5
: value === 'high'
? euiLightVars.euiColorVis7
: euiLightVars.euiColorVis9
}
>
{value}
</EuiHealth>
),
},
];
};
export const buildSeverityDescription = (label: string, value: string): ListItems[] => [
{
title: label,
description: <SeverityBadge value={value} />,
},
];

export const buildUrlsDescription = (label: string, values: string[]): ListItems[] => {
if (!isEmpty(values) && values.filter(val => !isEmpty(val)).length > 0) {
if (isNotEmptyArray(values)) {
return [
{
title: label,
description: (
<EuiListGroup
flush={true}
bordered={false}
listItems={values.map((val: string) => ({
label: val,
href: val,
iconType: 'link',
size: 'xs',
target: '_blank',
}))}
/>
<EuiFlexGroup gutterSize="none" alignItems="flexStart" direction="column">
{values.map((val: string) => (
<EuiFlexItem>
<ReferenceLinkItem
href={val}
target="_blank"
iconType="link"
size="xs"
flush="left"
>
{val}
</ReferenceLinkItem>
</EuiFlexItem>
))}
</EuiFlexGroup>
),
},
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { EuiDescriptionList, EuiFlexGroup, EuiFlexItem, EuiTextArea } from '@elastic/eui';
import { EuiDescriptionList, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { isEmpty, chunk, get, pick } from 'lodash/fp';
import React, { memo, useState } from 'react';
import styled from 'styled-components';

import {
IIndexPattern,
Expand All @@ -26,6 +25,7 @@ import {
buildSeverityDescription,
buildStringArrayDescription,
buildThreatsDescription,
buildUnorderedListArrayDescription,
buildUrlsDescription,
} from './helpers';

Expand All @@ -36,15 +36,6 @@ interface StepRuleDescriptionProps {
schema: FormSchema;
}

const EuiFlexItemWidth = styled(EuiFlexItem)<{ direction: string }>`
${props => (props.direction === 'row' ? 'width : 50%;' : 'width: 100%;')};
`;

const MyEuiTextArea = styled(EuiTextArea)`
max-width: 100%;
height: 80px;
`;

const StepRuleDescriptionComponent: React.FC<StepRuleDescriptionProps> = ({
data,
direction = 'row',
Expand All @@ -62,13 +53,24 @@ const StepRuleDescriptionComponent: React.FC<StepRuleDescriptionProps> = ({
],
[]
);

if (direction === 'row') {
return (
<EuiFlexGroup>
{chunk(Math.ceil(listItems.length / 2), listItems).map((chunkListItems, index) => (
<EuiFlexItem key={`description-step-rule-${index}`}>
<EuiDescriptionList listItems={chunkListItems} />
</EuiFlexItem>
))}
</EuiFlexGroup>
);
}

return (
<EuiFlexGroup gutterSize="none" direction={direction} justifyContent="spaceAround">
{chunk(Math.ceil(listItems.length / 2), listItems).map((chunkListItems, index) => (
<EuiFlexItemWidth direction={direction} key={`description-step-rule-${index}`} grow={false}>
<EuiDescriptionList listItems={chunkListItems} />
</EuiFlexItemWidth>
))}
<EuiFlexGroup>
<EuiFlexItem key={`description-step-rule`}>
<EuiDescriptionList listItems={listItems} />
</EuiFlexItem>
</EuiFlexGroup>
);
};
Expand Down Expand Up @@ -123,18 +125,28 @@ const getDescriptionItem = (
return [
{
title: label,
description: <MyEuiTextArea value={get(field, value)} readOnly={true} />,
description: get(field, value),
},
];
} else if (field === 'references') {
const urls: string[] = get(field, value);
return buildUrlsDescription(label, urls);
} else if (field === 'falsePositives') {
const values: string[] = get(field, value);
return buildUnorderedListArrayDescription(label, field, values);
} else if (Array.isArray(get(field, value))) {
const values: string[] = get(field, value);
return buildStringArrayDescription(label, field, values);
} else if (field === 'severity') {
const val: string = get(field, value);
return buildSeverityDescription(label, val);
} else if (field === 'riskScore') {
return [
{
title: label,
description: get(field, value),
},
];
} else if (field === 'timeline') {
const timeline = get(field, value) as FieldValueTimeline;
return [
Expand Down

0 comments on commit 93093a1

Please sign in to comment.