mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
[Security Solution] [Platform] Adds state to remember what was in data view or index pattern selection when switching between the two (#136448)
Co-authored-by: Khristinin Nikita <nikita.khristinin@elastic.co>
This commit is contained in:
parent
0824234fe1
commit
c2985c4daa
10 changed files with 157 additions and 67 deletions
|
@ -11,26 +11,17 @@ import type { EuiComboBoxOptionOption } from '@elastic/eui';
|
|||
import { EuiCallOut, EuiComboBox, EuiFormRow, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import type { DataViewListItem } from '@kbn/data-views-plugin/common';
|
||||
import type { DataViewBase } from '@kbn/es-query';
|
||||
import type { FieldHook } from '../../../../shared_imports';
|
||||
import { getFieldValidityAndErrorMessage } from '../../../../shared_imports';
|
||||
import * as i18n from './translations';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import type { DefineStepRule } from '../../../pages/detection_engine/rules/types';
|
||||
|
||||
interface DataViewSelectorProps {
|
||||
kibanaDataViews: { [x: string]: DataViewListItem };
|
||||
kibanaDataViews: Record<string, DataViewListItem>;
|
||||
field: FieldHook<DefineStepRule['dataViewId']>;
|
||||
setIndexPattern: (indexPattern: DataViewBase) => void;
|
||||
}
|
||||
|
||||
export const DataViewSelector = ({
|
||||
kibanaDataViews,
|
||||
field,
|
||||
setIndexPattern,
|
||||
}: DataViewSelectorProps) => {
|
||||
const { data } = useKibana().services;
|
||||
|
||||
export const DataViewSelector = ({ kibanaDataViews, field }: DataViewSelectorProps) => {
|
||||
let isInvalid;
|
||||
let errorMessage;
|
||||
let dataViewId: string | null | undefined;
|
||||
|
@ -62,7 +53,15 @@ export const DataViewSelector = ({
|
|||
: []
|
||||
);
|
||||
|
||||
const [selectedDataView, setSelectedDataView] = useState<DataViewListItem>();
|
||||
useEffect(() => {
|
||||
if (!selectedDataViewNotFound && dataViewId) {
|
||||
setSelectedOption([
|
||||
{ id: kibanaDataViews[dataViewId].id, label: kibanaDataViews[dataViewId].title },
|
||||
]);
|
||||
} else {
|
||||
setSelectedOption([]);
|
||||
}
|
||||
}, [dataViewId, field, kibanaDataViews, selectedDataViewNotFound]);
|
||||
|
||||
// TODO: optimize this, pass down array of data view ids
|
||||
// at the same time we grab the data views in the top level form component
|
||||
|
@ -75,17 +74,6 @@ export const DataViewSelector = ({
|
|||
: [];
|
||||
}, [kibanaDataViewsDefined, kibanaDataViews]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSingleDataView = async () => {
|
||||
if (selectedDataView != null) {
|
||||
const dv = await data.dataViews.get(selectedDataView.id);
|
||||
setIndexPattern(dv);
|
||||
}
|
||||
};
|
||||
|
||||
fetchSingleDataView();
|
||||
}, [data.dataViews, selectedDataView, setIndexPattern]);
|
||||
|
||||
const onChangeDataViews = (options: Array<EuiComboBoxOptionOption<string>>) => {
|
||||
const selectedDataViewOption = options;
|
||||
|
||||
|
@ -96,10 +84,9 @@ export const DataViewSelector = ({
|
|||
selectedDataViewOption.length > 0 &&
|
||||
selectedDataViewOption[0].id != null
|
||||
) {
|
||||
setSelectedDataView(kibanaDataViews[selectedDataViewOption[0].id]);
|
||||
field?.setValue(selectedDataViewOption[0].id);
|
||||
const selectedDataViewId = selectedDataViewOption[0].id;
|
||||
field?.setValue(selectedDataViewId);
|
||||
} else {
|
||||
setSelectedDataView(undefined);
|
||||
field?.setValue(undefined);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@ import type { FieldHook, ValidationError, ValidationFunc } from '../../../../sha
|
|||
import { isEqlRule } from '../../../../../common/detection_engine/utils';
|
||||
import { KibanaServices } from '../../../../common/lib/kibana';
|
||||
import type { DefineStepRule } from '../../../pages/detection_engine/rules/types';
|
||||
import { DataSourceType } from '../../../pages/detection_engine/rules/types';
|
||||
import { validateEql } from '../../../../common/hooks/eql/api';
|
||||
import type { FieldValueQueryBar } from '../query_bar';
|
||||
import * as i18n from './translations';
|
||||
|
@ -69,7 +70,11 @@ export const eqlValidator = async (
|
|||
const { data } = KibanaServices.get();
|
||||
let dataViewTitle = index?.join();
|
||||
let runtimeMappings = {};
|
||||
if (dataViewId != null) {
|
||||
if (
|
||||
dataViewId != null &&
|
||||
dataViewId !== '' &&
|
||||
formData.dataSourceType === DataSourceType.DataView
|
||||
) {
|
||||
const dataView = await data.dataViews.get(dataViewId);
|
||||
|
||||
dataViewTitle = dataView.title;
|
||||
|
|
|
@ -22,6 +22,7 @@ import type {
|
|||
RuleStep,
|
||||
DefineStepRule,
|
||||
} from '../../../pages/detection_engine/rules/types';
|
||||
import { DataSourceType } from '../../../pages/detection_engine/rules/types';
|
||||
import { fillEmptySeverityMappings } from '../../../pages/detection_engine/rules/helpers';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
|
||||
|
@ -54,6 +55,7 @@ export const stepDefineStepMLRule: DefineStepRule = {
|
|||
threatMapping: [],
|
||||
timeline: { id: null, title: null },
|
||||
eqlOptions: {},
|
||||
dataSourceType: DataSourceType.IndexPatterns,
|
||||
newTermsFields: ['host.ip'],
|
||||
historyWindowSize: '7d',
|
||||
};
|
||||
|
|
|
@ -36,11 +36,14 @@ import { isMlRule } from '../../../../../common/machine_learning/helpers';
|
|||
import { hasMlAdminPermissions } from '../../../../../common/machine_learning/has_ml_admin_permissions';
|
||||
import { hasMlLicense } from '../../../../../common/machine_learning/has_ml_license';
|
||||
import { useMlCapabilities } from '../../../../common/components/ml/hooks/use_ml_capabilities';
|
||||
import { useUiSetting$ } from '../../../../common/lib/kibana';
|
||||
import { useUiSetting$, useKibana } from '../../../../common/lib/kibana';
|
||||
import type { EqlOptionsSelected, FieldsEqlOptions } from '../../../../../common/search_strategy';
|
||||
import { filterRuleFieldsForType } from '../../../pages/detection_engine/rules/create/helpers';
|
||||
import {
|
||||
filterRuleFieldsForType,
|
||||
getStepDataDataSource,
|
||||
} from '../../../pages/detection_engine/rules/create/helpers';
|
||||
import type { DefineStepRule, RuleStepProps } from '../../../pages/detection_engine/rules/types';
|
||||
import { RuleStep } from '../../../pages/detection_engine/rules/types';
|
||||
import { RuleStep, DataSourceType } from '../../../pages/detection_engine/rules/types';
|
||||
import { StepRuleDescription } from '../description_step';
|
||||
import { QueryBarDefineRule } from '../query_bar';
|
||||
import { SelectRuleType } from '../select_rule_type';
|
||||
|
@ -78,11 +81,11 @@ import { NewTermsFields } from '../new_terms_fields';
|
|||
import { ScheduleItem } from '../schedule_item_form';
|
||||
import { DocLink } from '../../../../common/components/links_to_docs/doc_link';
|
||||
|
||||
const DATA_VIEW_SELECT_ID = 'dataView';
|
||||
const INDEX_PATTERN_SELECT_ID = 'indexPatterns';
|
||||
|
||||
const CommonUseField = getUseField({ component: Field });
|
||||
|
||||
const StyledVisibleContainer = styled.div<{ isVisible: boolean }>`
|
||||
display: ${(props) => (props.isVisible ? 'block' : 'none')};
|
||||
`;
|
||||
interface StepDefineRuleProps extends RuleStepProps {
|
||||
defaultValues?: DefineStepRule;
|
||||
}
|
||||
|
@ -119,6 +122,7 @@ export const stepDefineDefaultValue: DefineStepRule = {
|
|||
title: DEFAULT_TIMELINE_TITLE,
|
||||
},
|
||||
eqlOptions: {},
|
||||
dataSourceType: DataSourceType.IndexPatterns,
|
||||
newTermsFields: [],
|
||||
historyWindowSize: '7d',
|
||||
};
|
||||
|
@ -174,6 +178,7 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
|
|||
const [openTimelineSearch, setOpenTimelineSearch] = useState(false);
|
||||
const [indexModified, setIndexModified] = useState(false);
|
||||
const [threatIndexModified, setThreatIndexModified] = useState(false);
|
||||
const [dataViewTitle, setDataViewTitle] = useState<string>();
|
||||
|
||||
const [indicesConfig] = useUiSetting$<string[]>(DEFAULT_INDEX_KEY);
|
||||
const [threatIndicesConfig] = useUiSetting$<string[]>(DEFAULT_THREAT_INDEX_KEY);
|
||||
|
@ -202,6 +207,7 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
|
|||
threatMapping: formThreatMapping,
|
||||
machineLearningJobId: formMachineLearningJobId,
|
||||
anomalyThreshold: formAnomalyThreshold,
|
||||
dataSourceType: formDataSourceType,
|
||||
newTermsFields: formNewTermsFields,
|
||||
historyWindowSize: formHistoryWindowSize,
|
||||
},
|
||||
|
@ -221,6 +227,7 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
|
|||
'threatMapping',
|
||||
'machineLearningJobId',
|
||||
'anomalyThreshold',
|
||||
'dataSourceType',
|
||||
'newTermsFields',
|
||||
'historyWindowSize',
|
||||
],
|
||||
|
@ -236,6 +243,7 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
|
|||
const newTermsFields = formNewTermsFields ?? initialState.newTermsFields;
|
||||
const historyWindowSize = formHistoryWindowSize ?? initialState.historyWindowSize;
|
||||
const ruleType = formRuleType || initialState.ruleType;
|
||||
const dataSourceType = formDataSourceType || initialState.dataSourceType;
|
||||
|
||||
// if 'index' is selected, use these browser fields
|
||||
// otherwise use the dataview browserfields
|
||||
|
@ -243,24 +251,51 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
|
|||
const [optionsSelected, setOptionsSelected] = useState<EqlOptionsSelected>(
|
||||
defaultValues?.eqlOptions || {}
|
||||
);
|
||||
const [initIsIndexPatternLoading, { browserFields, indexPatterns: initIndexPattern }] =
|
||||
useFetchIndex(index, false);
|
||||
const [indexPattern, setIndexPattern] = useState<DataViewBase>(initIndexPattern);
|
||||
const [isIndexPatternLoading, setIsIndexPatternLoading] = useState(initIsIndexPatternLoading);
|
||||
const [dataSourceRadioIdSelected, setDataSourceRadioIdSelected] = useState(
|
||||
dataView == null || dataView === '' ? INDEX_PATTERN_SELECT_ID : DATA_VIEW_SELECT_ID
|
||||
const [isIndexPatternLoading, { browserFields, indexPatterns: initIndexPattern }] = useFetchIndex(
|
||||
index,
|
||||
false
|
||||
);
|
||||
const [indexPattern, setIndexPattern] = useState<DataViewBase>(initIndexPattern);
|
||||
|
||||
const { data } = useKibana().services;
|
||||
|
||||
// Why do we need this? to ensure the query bar auto-suggest gets the latest updates
|
||||
// when the index pattern changes
|
||||
// when we select new dataView
|
||||
// when we choose some other dataSourceType
|
||||
useEffect(() => {
|
||||
if (dataSourceRadioIdSelected === INDEX_PATTERN_SELECT_ID) {
|
||||
setIndexPattern(initIndexPattern);
|
||||
if (dataSourceType === DataSourceType.IndexPatterns) {
|
||||
if (!isIndexPatternLoading) {
|
||||
setIndexPattern(initIndexPattern);
|
||||
}
|
||||
}
|
||||
}, [initIndexPattern, dataSourceRadioIdSelected]);
|
||||
|
||||
if (dataSourceType === DataSourceType.DataView) {
|
||||
const fetchDataView = async () => {
|
||||
if (dataView != null) {
|
||||
const dv = await data.dataViews.get(dataView);
|
||||
setDataViewTitle(dv.title);
|
||||
setIndexPattern(dv);
|
||||
}
|
||||
};
|
||||
|
||||
fetchDataView();
|
||||
}
|
||||
}, [dataSourceType, isIndexPatternLoading, data, dataView, initIndexPattern]);
|
||||
|
||||
// Callback for when user toggles between Data Views and Index Patterns
|
||||
const onChangeDataSource = (optionId: string) => {
|
||||
setDataSourceRadioIdSelected(optionId);
|
||||
};
|
||||
const onChangeDataSource = useCallback(
|
||||
(optionId: string) => {
|
||||
form.setFieldValue('dataSourceType', optionId);
|
||||
form.getFields().index.reset({
|
||||
resetValue: false,
|
||||
});
|
||||
form.getFields().dataViewId.reset({
|
||||
resetValue: false,
|
||||
});
|
||||
},
|
||||
[form]
|
||||
);
|
||||
|
||||
const [aggFields, setAggregatableFields] = useState<DataViewFieldBase[]>([]);
|
||||
|
||||
|
@ -433,28 +468,26 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
|
|||
const dataViewIndexPatternToggleButtonOptions: EuiButtonGroupOptionProps[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
id: INDEX_PATTERN_SELECT_ID,
|
||||
id: DataSourceType.IndexPatterns,
|
||||
label: i18nCore.translate(
|
||||
'xpack.securitySolution.ruleDefine.indexTypeSelect.indexPattern',
|
||||
{
|
||||
defaultMessage: 'Index Patterns',
|
||||
}
|
||||
),
|
||||
iconType:
|
||||
dataSourceRadioIdSelected === INDEX_PATTERN_SELECT_ID ? 'checkInCircleFilled' : 'empty',
|
||||
'data-test-subj': `rule-index-toggle-${INDEX_PATTERN_SELECT_ID}`,
|
||||
iconType: dataSourceType === DataSourceType.IndexPatterns ? 'checkInCircleFilled' : 'empty',
|
||||
'data-test-subj': `rule-index-toggle-${DataSourceType.IndexPatterns}`,
|
||||
},
|
||||
{
|
||||
id: DATA_VIEW_SELECT_ID,
|
||||
id: DataSourceType.DataView,
|
||||
label: i18nCore.translate('xpack.securitySolution.ruleDefine.indexTypeSelect.dataView', {
|
||||
defaultMessage: 'Data View',
|
||||
}),
|
||||
iconType:
|
||||
dataSourceRadioIdSelected === DATA_VIEW_SELECT_ID ? 'checkInCircleFilled' : 'empty',
|
||||
'data-test-subj': `rule-index-toggle-${DATA_VIEW_SELECT_ID}`,
|
||||
iconType: dataSourceType === DataSourceType.DataView ? 'checkInCircleFilled' : 'empty',
|
||||
'data-test-subj': `rule-index-toggle-${DataSourceType.DataView}`,
|
||||
},
|
||||
],
|
||||
[dataSourceRadioIdSelected]
|
||||
[dataSourceType]
|
||||
);
|
||||
|
||||
const DataViewSelectorMemo = useMemo(() => {
|
||||
|
@ -465,8 +498,6 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
|
|||
component={DataViewSelector}
|
||||
componentProps={{
|
||||
kibanaDataViews,
|
||||
setIndexPattern,
|
||||
setIsIndexPatternLoading,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
@ -503,7 +534,7 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
|
|||
isFullWidth={true}
|
||||
legend="Rule index pattern or data view selector"
|
||||
data-test-subj="dataViewIndexPatternButtonGroup"
|
||||
idSelected={dataSourceRadioIdSelected}
|
||||
idSelected={dataSourceType}
|
||||
onChange={onChangeDataSource}
|
||||
options={dataViewIndexPatternToggleButtonOptions}
|
||||
color="primary"
|
||||
|
@ -512,9 +543,10 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
|
|||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem>
|
||||
{dataSourceRadioIdSelected === DATA_VIEW_SELECT_ID ? (
|
||||
DataViewSelectorMemo
|
||||
) : (
|
||||
<StyledVisibleContainer isVisible={dataSourceType === DataSourceType.DataView}>
|
||||
{DataViewSelectorMemo}
|
||||
</StyledVisibleContainer>
|
||||
<StyledVisibleContainer isVisible={dataSourceType === DataSourceType.IndexPatterns}>
|
||||
<CommonUseField
|
||||
path="index"
|
||||
config={{
|
||||
|
@ -534,17 +566,18 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
|
|||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</StyledVisibleContainer>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</RuleTypeEuiFormRow>
|
||||
);
|
||||
}, [
|
||||
dataSourceRadioIdSelected,
|
||||
dataSourceType,
|
||||
dataViewIndexPatternToggleButtonOptions,
|
||||
DataViewSelectorMemo,
|
||||
indexModified,
|
||||
handleResetIndices,
|
||||
onChangeDataSource,
|
||||
]);
|
||||
|
||||
const QueryBarMemo = useMemo(
|
||||
|
@ -619,19 +652,36 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
|
|||
[indexPattern]
|
||||
);
|
||||
|
||||
const dataForDescription: Partial<DefineStepRule> = getStepDataDataSource(initialState);
|
||||
|
||||
if (dataSourceType === DataSourceType.DataView) {
|
||||
dataForDescription.dataViewTitle = dataViewTitle;
|
||||
}
|
||||
|
||||
return isReadOnlyView ? (
|
||||
<StepContentWrapper data-test-subj="definitionRule" addPadding={addPadding}>
|
||||
<StepRuleDescription
|
||||
columns={descriptionColumns}
|
||||
indexPatterns={indexPattern}
|
||||
schema={filterRuleFieldsForType(schema, ruleType)}
|
||||
data={filterRuleFieldsForType(initialState, ruleType)}
|
||||
data={filterRuleFieldsForType(dataForDescription, ruleType)}
|
||||
/>
|
||||
</StepContentWrapper>
|
||||
) : (
|
||||
<>
|
||||
<StepContentWrapper addPadding={!isUpdateView}>
|
||||
<Form form={form} data-test-subj="stepDefineRule">
|
||||
<StyledVisibleContainer isVisible={false}>
|
||||
<UseField
|
||||
path="dataSourceType"
|
||||
componentProps={{
|
||||
euiFieldProps: {
|
||||
fullWidth: true,
|
||||
placeholder: '',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</StyledVisibleContainer>
|
||||
<UseField
|
||||
path="ruleType"
|
||||
component={SelectRuleType}
|
||||
|
|
|
@ -27,6 +27,7 @@ import type { FieldValueQueryBar } from '../query_bar';
|
|||
import type { ERROR_CODE, FormSchema, ValidationFunc } from '../../../../shared_imports';
|
||||
import { FIELD_TYPES, fieldValidators } from '../../../../shared_imports';
|
||||
import type { DefineStepRule } from '../../../pages/detection_engine/rules/types';
|
||||
import { DataSourceType } from '../../../pages/detection_engine/rules/types';
|
||||
import { debounceAsync, eqlValidator } from '../eql_query_bar/validators';
|
||||
import {
|
||||
CUSTOM_QUERY_REQUIRED,
|
||||
|
@ -56,7 +57,8 @@ export const schema: FormSchema<DefineStepRule> = {
|
|||
...args: Parameters<ValidationFunc>
|
||||
): ReturnType<ValidationFunc<{}, ERROR_CODE>> | undefined => {
|
||||
const [{ formData }] = args;
|
||||
const skipValidation = isMlRule(formData.ruleType) || formData.dataViewId != null;
|
||||
const skipValidation =
|
||||
isMlRule(formData.ruleType) || formData.dataSourceType !== DataSourceType.IndexPatterns;
|
||||
|
||||
if (skipValidation) {
|
||||
return;
|
||||
|
@ -94,10 +96,11 @@ export const schema: FormSchema<DefineStepRule> = {
|
|||
// the dropdown defaults the dataViewId to an empty string somehow on render..
|
||||
// need to figure this out.
|
||||
const notEmptyDataViewId = formData.dataViewId != null && formData.dataViewId !== '';
|
||||
|
||||
const skipValidation =
|
||||
isMlRule(formData.ruleType) ||
|
||||
((formData.index != null || notEmptyDataViewId) &&
|
||||
!(formData.index != null && notEmptyDataViewId));
|
||||
notEmptyDataViewId ||
|
||||
formData.dataSourceType !== DataSourceType.DataView;
|
||||
|
||||
if (skipValidation) {
|
||||
return;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import { FilterStateStore } from '@kbn/es-query';
|
||||
import type { Rule } from '../../../../../containers/detection_engine/rules';
|
||||
import type { AboutStepRule, ActionsStepRule, DefineStepRule, ScheduleStepRule } from '../../types';
|
||||
import { DataSourceType } from '../../types';
|
||||
import type { FieldValueQueryBar } from '../../../../../components/rules/query_bar';
|
||||
import { fillEmptySeverityMappings } from '../../helpers';
|
||||
import { getThreatMock } from '../../../../../../../common/detection_engine/schemas/types/threat.mock';
|
||||
|
@ -216,6 +217,7 @@ export const mockDefineStepRule = (): DefineStepRule => ({
|
|||
},
|
||||
},
|
||||
eqlOptions: {},
|
||||
dataSourceType: DataSourceType.IndexPatterns,
|
||||
newTermsFields: ['host.ip'],
|
||||
historyWindowSize: '7d',
|
||||
});
|
||||
|
|
|
@ -9,6 +9,7 @@ import { has, isEmpty } from 'lodash/fp';
|
|||
import type { Unit } from '@kbn/datemath';
|
||||
import moment from 'moment';
|
||||
import deepmerge from 'deepmerge';
|
||||
import omit from 'lodash/omit';
|
||||
|
||||
import type {
|
||||
ExceptionListType,
|
||||
|
@ -39,6 +40,7 @@ import type {
|
|||
RuleStepsFormData,
|
||||
RuleStep,
|
||||
} from '../types';
|
||||
import { DataSourceType } from '../types';
|
||||
import type { FieldValueQueryBar } from '../../../../components/rules/query_bar';
|
||||
import type { CreateRulesSchema } from '../../../../../../common/detection_engine/schemas/request';
|
||||
import { stepDefineDefaultValue } from '../../../../components/rules/step_define_rule';
|
||||
|
@ -336,9 +338,34 @@ export const filterEmptyThreats = (threats: Threats): Threats => {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* remove unused data source.
|
||||
* Ex: rule is using a data view so we should not
|
||||
* write an index property on the rule form.
|
||||
* @param defineStepData
|
||||
* @returns DefineStepRule
|
||||
*/
|
||||
export const getStepDataDataSource = (
|
||||
defineStepData: DefineStepRule
|
||||
): Omit<DefineStepRule, 'dataViewId' | 'index' | 'dataSourceType'> & {
|
||||
index?: string[];
|
||||
dataViewId?: string;
|
||||
} => {
|
||||
const copiedStepData = { ...defineStepData };
|
||||
if (defineStepData.dataSourceType === DataSourceType.DataView) {
|
||||
return omit(copiedStepData, ['index', 'dataSourceType']);
|
||||
} else if (defineStepData.dataSourceType === DataSourceType.IndexPatterns) {
|
||||
return omit(copiedStepData, ['dataViewId', 'dataSourceType']);
|
||||
}
|
||||
return copiedStepData;
|
||||
};
|
||||
|
||||
export const formatDefineStepData = (defineStepData: DefineStepRule): DefineStepRuleJson => {
|
||||
const ruleFields = filterRuleFieldsForType(defineStepData, defineStepData.ruleType);
|
||||
const stepData = getStepDataDataSource(defineStepData);
|
||||
|
||||
const ruleFields = filterRuleFieldsForType(stepData, stepData.ruleType);
|
||||
const { ruleType, timeline } = ruleFields;
|
||||
|
||||
const baseFields = {
|
||||
type: ruleType,
|
||||
...(timeline.id != null &&
|
||||
|
|
|
@ -50,6 +50,8 @@ describe('rule helpers', () => {
|
|||
const defineRuleStepData = {
|
||||
ruleType: 'saved_query',
|
||||
anomalyThreshold: 50,
|
||||
dataSourceType: 'indexPatterns',
|
||||
dataViewId: undefined,
|
||||
index: ['auditbeat-*'],
|
||||
machineLearningJobId: [],
|
||||
queryBar: {
|
||||
|
@ -215,6 +217,8 @@ describe('rule helpers', () => {
|
|||
const expected = {
|
||||
ruleType: 'saved_query',
|
||||
anomalyThreshold: 50,
|
||||
dataSourceType: 'indexPatterns',
|
||||
dataViewId: undefined,
|
||||
machineLearningJobId: [],
|
||||
index: ['auditbeat-*'],
|
||||
queryBar: {
|
||||
|
@ -266,6 +270,8 @@ describe('rule helpers', () => {
|
|||
const expected = {
|
||||
ruleType: 'saved_query',
|
||||
anomalyThreshold: 50,
|
||||
dataSourceType: 'indexPatterns',
|
||||
dataViewId: undefined,
|
||||
machineLearningJobId: [],
|
||||
index: ['auditbeat-*'],
|
||||
queryBar: {
|
||||
|
|
|
@ -33,6 +33,7 @@ import type {
|
|||
ScheduleStepRule,
|
||||
ActionsStepRule,
|
||||
} from './types';
|
||||
import { DataSourceType } from './types';
|
||||
import { severityOptions } from '../../../components/rules/step_about_rule/data';
|
||||
|
||||
export interface GetStepsData {
|
||||
|
@ -120,6 +121,7 @@ export const getDefineStepsData = (rule: Rule): DefineStepRule => ({
|
|||
eventCategoryField: rule.event_category_override,
|
||||
tiebreakerField: rule.tiebreaker_field,
|
||||
},
|
||||
dataSourceType: rule.data_view_id ? DataSourceType.DataView : DataSourceType.IndexPatterns,
|
||||
newTermsFields: rule.new_terms_fields ?? [],
|
||||
historyWindowSize: rule.history_window_start
|
||||
? convertHistoryStartToSize(rule.history_window_start)
|
||||
|
|
|
@ -133,6 +133,11 @@ export interface AboutStepRiskScore {
|
|||
isMappingChecked: boolean;
|
||||
}
|
||||
|
||||
export enum DataSourceType {
|
||||
IndexPatterns = 'indexPatterns',
|
||||
DataView = 'dataView',
|
||||
}
|
||||
|
||||
/**
|
||||
* add / update data source types to show XOR relationship between 'index' and 'dataViewId' fields
|
||||
* Maybe something with io-ts?
|
||||
|
@ -153,6 +158,7 @@ export interface DefineStepRule {
|
|||
threatQueryBar: FieldValueQueryBar;
|
||||
threatMapping: ThreatMapping;
|
||||
eqlOptions: EqlOptionsSelected;
|
||||
dataSourceType: DataSourceType;
|
||||
newTermsFields: string[];
|
||||
historyWindowSize: string;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue