Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SIEM] Detection Engine Create Rule Design Review #1 #54442

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import {
EuiBadge,
EuiHealth,
EuiIconTip,
EuiLink,
EuiTextColor,
Expand All @@ -17,7 +16,6 @@ import {
} 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 @@ -88,21 +87,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 @@ -9,7 +9,6 @@ import {
EuiLoadingSpinner,
EuiFlexGroup,
EuiFlexItem,
EuiHealth,
EuiLink,
EuiText,
EuiListGroup,
Expand All @@ -27,6 +26,10 @@ 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';

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

const EuiBadgeWrap = styled(EuiBadge)`
.euiBadge__text {
Expand Down Expand Up @@ -148,12 +151,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,31 +199,15 @@ 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,
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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 { upperFirst } from 'lodash/fp';
import React from 'react';
import { EuiHealth } from '@elastic/eui';
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';

interface Props {
value: string;
}

const SeverityBadgeComponent: React.FC<Props> = ({ value }) => (
<EuiHealth
color={
value === 'low'
? euiLightVars.euiColorVis0
: value === 'medium'
? euiLightVars.euiColorVis5
: value === 'high'
? euiLightVars.euiColorVis7
: euiLightVars.euiColorVis9
}
>
{upperFirst(value)}
</EuiHealth>
);

export const SeverityBadge = React.memo(SeverityBadgeComponent);
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import styled from 'styled-components';
import { EuiHealth } from '@elastic/eui';
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
import React from 'react';
Expand All @@ -16,22 +17,30 @@ interface SeverityOptionItem {
inputDisplay: React.ReactElement;
}

const StyledEuiHealth = styled(EuiHealth)`
line-height: inherit;
`;

export const severityOptions: SeverityOptionItem[] = [
{
value: 'low',
inputDisplay: <EuiHealth color={euiLightVars.euiColorVis0}>{I18n.LOW}</EuiHealth>,
inputDisplay: <StyledEuiHealth color={euiLightVars.euiColorVis0}>{I18n.LOW}</StyledEuiHealth>,
},
{
value: 'medium',
inputDisplay: <EuiHealth color={euiLightVars.euiColorVis5}>{I18n.MEDIUM} </EuiHealth>,
inputDisplay: (
<StyledEuiHealth color={euiLightVars.euiColorVis5}>{I18n.MEDIUM}</StyledEuiHealth>
),
},
{
value: 'high',
inputDisplay: <EuiHealth color={euiLightVars.euiColorVis7}>{I18n.HIGH} </EuiHealth>,
inputDisplay: <StyledEuiHealth color={euiLightVars.euiColorVis7}>{I18n.HIGH}</StyledEuiHealth>,
},
{
value: 'critical',
inputDisplay: <EuiHealth color={euiLightVars.euiColorVis9}>{I18n.CRITICAL} </EuiHealth>,
inputDisplay: (
<StyledEuiHealth color={euiLightVars.euiColorVis9}>{I18n.CRITICAL}</StyledEuiHealth>
),
},
];

Expand Down
Loading