Skip to content

Commit

Permalink
Move timeline template to Define step of Rule creation
Browse files Browse the repository at this point in the history
This required a refactor/simplification of the step_define_rule logic to
make things work. In retrospect I think that the issue was we were not
handling incoming `defaultValues` props well, which was causing local
component state to be lost.

Now that we're doing a merge and removed a few unneeded local useStates,
things are a) working and b) cleaner
  • Loading branch information
rylnd committed Mar 20, 2020
1 parent 1a1e2e7 commit 91a60b6
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
*/

import { AboutStepRule } from '../../types';
import { DEFAULT_TIMELINE_TITLE } from '../../../../../components/timeline/translations';

export const threatDefault = [
{
Expand All @@ -24,10 +23,6 @@ export const stepAboutDefaultValue: AboutStepRule = {
references: [''],
falsePositives: [''],
tags: [],
timeline: {
id: null,
title: DEFAULT_TIMELINE_TITLE,
},
threat: threatDefault,
note: '',
};
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import { stepAboutDefaultValue } from './default_value';
import { isUrlInvalid } from './helpers';
import { schema } from './schema';
import * as I18n from './translations';
import { PickTimeline } from '../pick_timeline';
import { StepContentWrapper } from '../step_content_wrapper';
import { MarkdownEditorForm } from '../../../../../components/markdown_editor/form';

Expand Down Expand Up @@ -216,15 +215,6 @@ const StepAboutRuleComponent: FC<StepAboutRuleProps> = ({
buttonContent={AdvancedSettingsAccordionButton}
>
<EuiSpacer size="m" />
<UseField
path="timeline"
component={PickTimeline}
componentProps={{
idAria: 'detectionEngineStepAboutRuleTimeline',
isDisabled: isLoading,
dataTestSubj: 'detectionEngineStepAboutRuleTimeline',
}}
/>
<UseField
path="references"
component={AddItem}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,21 +91,6 @@ export const schema: FormSchema = {
}
),
},
timeline: {
label: i18n.translate(
'xpack.siem.detectionEngine.createRule.stepAboutRule.fieldTimelineTemplateLabel',
{
defaultMessage: 'Timeline template',
}
),
helpText: i18n.translate(
'xpack.siem.detectionEngine.createRule.stepAboutRule.fieldTimelineTemplateHelpText',
{
defaultMessage:
'Select an existing timeline to use as a template when investigating generated signals.',
}
),
},
references: {
label: i18n.translate(
'xpack.siem.detectionEngine.createRule.stepAboutRule.fieldReferenceUrlsLabel',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import deepEqual from 'fast-deep-equal';
import { IIndexPattern } from '../../../../../../../../../../src/plugins/data/public';
import { useFetchIndexPatterns } from '../../../../../containers/detection_engine/rules';
import { DEFAULT_INDEX_KEY } from '../../../../../../common/constants';
import { DEFAULT_TIMELINE_TITLE } from '../../../../../components/timeline/translations';
import { useUiSetting$ } from '../../../../../lib/kibana';
import { setFieldValue, isMlRule } from '../../helpers';
import * as RuleI18n from '../../translations';
Expand All @@ -29,6 +30,7 @@ import { QueryBarDefineRule } from '../query_bar';
import { SelectRuleType } from '../select_rule_type';
import { AnomalyThresholdSlider } from '../anomaly_threshold_slider';
import { MlJobSelect } from '../ml_job_select';
import { PickTimeline } from '../pick_timeline';
import { StepContentWrapper } from '../step_content_wrapper';
import {
Field,
Expand Down Expand Up @@ -60,6 +62,10 @@ const stepDefineDefaultValue: DefineStepRule = {
filters: [],
saved_id: undefined,
},
timeline: {
id: null,
title: DEFAULT_TIMELINE_TITLE,
},
};

const MyLabelButton = styled(EuiButtonEmpty)`
Expand All @@ -76,23 +82,6 @@ MyLabelButton.defaultProps = {
flush: 'right',
};

const getStepDefaultValue = (
indicesConfig: string[],
defaultValues: DefineStepRule | null
): DefineStepRule => {
if (defaultValues != null) {
return {
...defaultValues,
isNew: false,
};
} else {
return {
...stepDefineDefaultValue,
index: indicesConfig != null ? indicesConfig : [],
};
}
};

const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
addPadding = false,
defaultValues,
Expand All @@ -104,18 +93,16 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
setStepData,
}) => {
const [openTimelineSearch, setOpenTimelineSearch] = useState(false);
const [localUseIndicesConfig, setLocalUseIndicesConfig] = useState(false);
const [indexModified, setIndexModified] = useState(false);
const [localIsMlRule, setIsMlRule] = useState(false);
const [indicesConfig] = useUiSetting$<string[]>(DEFAULT_INDEX_KEY);
const [mylocalIndicesConfig, setMyLocalIndicesConfig] = useState(
defaultValues != null ? defaultValues.index : indicesConfig ?? []
);
const [myStepData, setMyStepData] = useState<DefineStepRule>({
...stepDefineDefaultValue,
index: indicesConfig ?? [],
});
const [
{ browserFields, indexPatterns: indexPatternQueryBar, isLoading: indexPatternLoadingQueryBar },
] = useFetchIndexPatterns(mylocalIndicesConfig);
const [myStepData, setMyStepData] = useState<DefineStepRule>(
getStepDefaultValue(indicesConfig, null)
);
] = useFetchIndexPatterns(myStepData.index);

const { form } = useForm({
defaultValue: myStepData,
Expand All @@ -136,15 +123,13 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
}, [form]);

useEffect(() => {
if (indicesConfig != null && defaultValues != null) {
const myDefaultValues = getStepDefaultValue(indicesConfig, defaultValues);
if (!deepEqual(myDefaultValues, myStepData)) {
setMyStepData(myDefaultValues);
setLocalUseIndicesConfig(deepEqual(myDefaultValues.index, indicesConfig));
setFieldValue(form, schema, myDefaultValues);
}
const { isNew, ...values } = myStepData;
if (defaultValues != null && !deepEqual(values, defaultValues)) {
const newValues = { ...values, ...defaultValues, isNew: false };
setMyStepData(newValues);
setFieldValue(form, schema, newValues);
}
}, [defaultValues, indicesConfig]);
}, [defaultValues, setMyStepData, setFieldValue]);

useEffect(() => {
if (setForm != null) {
Expand Down Expand Up @@ -191,7 +176,7 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
path="index"
config={{
...schema.index,
labelAppend: !localUseIndicesConfig ? (
labelAppend: indexModified ? (
<MyLabelButton onClick={handleResetIndices} iconType="refresh">
{i18n.RESET_DEFAULT_INDEX}
</MyLabelButton>
Expand Down Expand Up @@ -238,17 +223,22 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
<UseField path="anomalyThreshold" component={AnomalyThresholdSlider} />
</>
</EuiFormRow>
<UseField
path="timeline"
component={PickTimeline}
componentProps={{
idAria: 'detectionEngineStepDefineRuleTimeline',
isDisabled: isLoading,
dataTestSubj: 'detectionEngineStepDefineRuleTimeline',
}}
/>
<FormDataProvider pathsToWatch={['index', 'ruleType']}>
{({ index, ruleType }) => {
if (index != null) {
if (deepEqual(index, indicesConfig) && !localUseIndicesConfig) {
setLocalUseIndicesConfig(true);
}
if (!deepEqual(index, indicesConfig) && localUseIndicesConfig) {
setLocalUseIndicesConfig(false);
}
if (index != null && !isEmpty(index) && !deepEqual(index, mylocalIndicesConfig)) {
setMyLocalIndicesConfig(index);
if (deepEqual(index, indicesConfig) && indexModified) {
setIndexModified(false);
} else if (!deepEqual(index, indicesConfig) && !indexModified) {
setIndexModified(true);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,19 @@ export const schema: FormSchema = {
},
],
},
timeline: {
label: i18n.translate(
'xpack.siem.detectionEngine.createRule.stepAboutRule.fieldTimelineTemplateLabel',
{
defaultMessage: 'Timeline template',
}
),
helpText: i18n.translate(
'xpack.siem.detectionEngine.createRule.stepAboutRule.fieldTimelineTemplateHelpText',
{
defaultMessage:
'Select an existing timeline to use as a template when investigating generated signals.',
}
),
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -64,27 +64,34 @@ export const filterRuleFieldsForType = <T extends RuleFields>(fields: T, type: R

export const formatDefineStepData = (defineStepData: DefineStepRule): DefineStepRuleJson => {
const ruleFields = filterRuleFieldsForType(defineStepData, defineStepData.ruleType);
const { ruleType, timeline } = ruleFields;
const baseFields = {
type: ruleType,
...(timeline.id != null &&
timeline.title != null && {
timeline_id: timeline.id,
timeline_title: timeline.title,
}),
};

if (isMlFields(ruleFields)) {
const { anomalyThreshold, machineLearningJobId, isNew, ruleType, ...rest } = ruleFields;
return {
...rest,
type: ruleType,
anomaly_threshold: anomalyThreshold,
machine_learning_job_id: machineLearningJobId,
};
} else {
const { queryBar, isNew, ruleType, ...rest } = ruleFields;
return {
...rest,
type: ruleType,
filters: queryBar?.filters,
language: queryBar?.query?.language,
query: queryBar?.query?.query as string,
saved_id: queryBar?.saved_id,
...(ruleType === 'query' && queryBar?.saved_id ? { type: 'saved_query' as RuleType } : {}),
};
}
const typeFields = isMlFields(ruleFields)
? {
anomaly_threshold: ruleFields.anomalyThreshold,
machine_learning_job_id: ruleFields.machineLearningJobId,
}
: {
filters: ruleFields.queryBar?.filters,
language: ruleFields.queryBar?.query?.language,
query: ruleFields.queryBar?.query?.query as string,
saved_id: ruleFields.queryBar?.saved_id,
...(ruleType === 'query' &&
ruleFields.queryBar?.saved_id && { type: 'saved_query' as RuleType }),
};

return {
...baseFields,
...typeFields,
};
};

export const formatScheduleStepData = (scheduleData: ScheduleStepRule): ScheduleStepRuleJson => {
Expand All @@ -108,26 +115,11 @@ export const formatScheduleStepData = (scheduleData: ScheduleStepRule): Schedule
};

export const formatAboutStepData = (aboutStepData: AboutStepRule): AboutStepRuleJson => {
const {
falsePositives,
references,
riskScore,
threat,
timeline,
isNew,
note,
...rest
} = aboutStepData;
const { falsePositives, references, riskScore, threat, isNew, note, ...rest } = aboutStepData;
return {
false_positives: falsePositives.filter(item => !isEmpty(item)),
references: references.filter(item => !isEmpty(item)),
risk_score: riskScore,
...(timeline.id != null && timeline.title != null
? {
timeline_id: timeline.id,
timeline_title: timeline.title,
}
: {}),
threat: threat
.filter(singleThreat => singleThreat.tactic.name !== 'none')
.map(singleThreat => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ export interface AboutStepRule extends StepRuleData {
references: string[];
falsePositives: string[];
tags: string[];
timeline: FieldValueTimeline;
threat: IMitreEnterpriseAttack[];
note: string;
}
Expand All @@ -73,6 +72,7 @@ export interface DefineStepRule extends StepRuleData {
machineLearningJobId: string;
queryBar: FieldValueQueryBar;
ruleType: RuleType;
timeline: FieldValueTimeline;
}

export interface ScheduleStepRule extends StepRuleData {
Expand All @@ -90,6 +90,8 @@ export interface DefineStepRuleJson {
saved_id?: string;
query?: string;
language?: string;
timeline_id?: string;
timeline_title?: string;
type: RuleType;
}

Expand All @@ -101,8 +103,6 @@ export interface AboutStepRuleJson {
references: string[];
false_positives: string[];
tags: string[];
timeline_id?: string;
timeline_title?: string;
threat: IMitreEnterpriseAttack[];
note?: string;
}
Expand Down

0 comments on commit 91a60b6

Please sign in to comment.