-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Security Solution] Add history_window_start
and new_terms_fields
editable fields
#200304
base: main
Are you sure you want to change the base?
Changes from 9 commits
d79f204
8f9cc18
1170e92
a67e1b0
7a786be
a9591c7
2bfd937
65d5d9a
e7942e2
4284e9a
ead30e0
28081a2
762530b
3e3fe80
399285c
09e68ef
c312627
d8ed050
3ce17c7
b88f566
2668271
adc3091
7a3f474
4221186
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { useMemo } from 'react'; | ||
import type { FieldSpec } from '@kbn/data-views-plugin/common'; | ||
import type { DataViewFieldBase } from '@kbn/es-query'; | ||
import { getTermsAggregationFields } from '../../detection_engine/rule_creation_ui/components/step_define_rule/utils'; | ||
|
||
export function useTermsAggregationFields(fields?: DataViewFieldBase[]) { | ||
const termsAggregationFields = useMemo( | ||
/** | ||
* Typecasting to FieldSpec because fields is | ||
* typed as DataViewFieldBase[] which does not have | ||
* the 'aggregatable' property, however the type is incorrect | ||
* | ||
* fields does contain elements with the aggregatable property. | ||
* We will need to determine where these types are defined and | ||
* figure out where the discrepancy is. | ||
*/ | ||
() => getTermsAggregationFields((fields as FieldSpec[]) ?? []), | ||
[fields] | ||
); | ||
|
||
return termsAggregationFields; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
/** | ||
* Converts a date math string to a duration string by removing the 'now-' prefix. | ||
* | ||
* @param historyStart - Date math string to convert. For example, "now-30d". | ||
* @returns Resulting duration string. For example, "30d". | ||
*/ | ||
export const convertDateMathToDuration = (dateMathString: string): string => { | ||
if (dateMathString.startsWith('now-')) { | ||
return dateMathString.substring(4); | ||
} | ||
|
||
return dateMathString; | ||
}; | ||
|
||
/** | ||
* Converts a duration string to a dateMath string by adding the 'now-' prefix. | ||
* | ||
* @param durationString - Duration string to convert. For example, "30d". | ||
* @returns Resulting date math string. For example, "now-30d". | ||
*/ | ||
export const convertDurationToDateMath = (durationString: string): string => | ||
`now-${durationString}`; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,58 @@ | ||||||||||||||||||||||||||||
/* | ||||||||||||||||||||||||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||||||||||||||||||||||||||||
* or more contributor license agreements. Licensed under the Elastic License | ||||||||||||||||||||||||||||
* 2.0; you may not use this file except in compliance with the Elastic License | ||||||||||||||||||||||||||||
* 2.0. | ||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
import React from 'react'; | ||||||||||||||||||||||||||||
import { i18n } from '@kbn/i18n'; | ||||||||||||||||||||||||||||
import { ScheduleItemField } from '../schedule_item_field'; | ||||||||||||||||||||||||||||
import type { ERROR_CODE, ValidationFunc } from '../../../../shared_imports'; | ||||||||||||||||||||||||||||
import { type FieldConfig, UseField } from '../../../../shared_imports'; | ||||||||||||||||||||||||||||
import { type HistoryWindowStart } from '../../../../../common/api/detection_engine'; | ||||||||||||||||||||||||||||
import { historyWindowStartValidationFactory } from '../../../rule_creation_ui/validators/history_window_start_validator_factory'; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
const COMPONENT_PROPS = { | ||||||||||||||||||||||||||||
idAria: 'historyWindowSize', | ||||||||||||||||||||||||||||
dataTestSubj: 'historyWindowSize', | ||||||||||||||||||||||||||||
timeTypes: ['m', 'h', 'd'], | ||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
interface HistoryWindowStartEditProps { | ||||||||||||||||||||||||||||
path: string; | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
export function HistoryWindowStartEdit({ path }: HistoryWindowStartEditProps): JSX.Element { | ||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||
<UseField | ||||||||||||||||||||||||||||
path={path} | ||||||||||||||||||||||||||||
config={HISTORY_WINDOW_START_FIELD_CONFIG} | ||||||||||||||||||||||||||||
component={ScheduleItemField} | ||||||||||||||||||||||||||||
componentProps={COMPONENT_PROPS} | ||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
const HISTORY_WINDOW_START_FIELD_CONFIG: FieldConfig<HistoryWindowStart> = { | ||||||||||||||||||||||||||||
label: i18n.translate( | ||||||||||||||||||||||||||||
'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.historyWindowSizeLabel', | ||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||
defaultMessage: 'History Window Size', | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||
helpText: i18n.translate( | ||||||||||||||||||||||||||||
'xpack.securitySolution.detectionEngine.createRule.stepScheduleRule.historyWindowSizeHelpText', | ||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||
defaultMessage: "New terms rules only alert if terms don't appear in historical data.", | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||
validations: [ | ||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||
validator: ( | ||||||||||||||||||||||||||||
...args: Parameters<ValidationFunc> | ||||||||||||||||||||||||||||
): ReturnType<ValidationFunc<{}, ERROR_CODE>> | undefined => | ||||||||||||||||||||||||||||
historyWindowStartValidationFactory(...args), | ||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
export { HistoryWindowStartEdit } from './history_window_start_edit'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
export { NewTermsFieldsEdit } from './new_terms_fields_edit'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import React, { memo } from 'react'; | ||
import { i18n } from '@kbn/i18n'; | ||
import type { ERROR_CODE, ValidationFunc } from '../../../../shared_imports'; | ||
import { FIELD_TYPES, UseField } from '../../../../shared_imports'; | ||
import { NewTermsFieldsField } from './new_terms_fields_field'; | ||
import { newTermsFieldsValidatorFactory } from '../../../rule_creation_ui/validators/new_terms_fields_validator_factory'; | ||
|
||
interface NewTermsFieldsEditProps { | ||
path: string; | ||
fieldNames: string[]; | ||
} | ||
|
||
export const NewTermsFieldsEdit = memo(function NewTermsFieldsEdit({ | ||
path, | ||
fieldNames, | ||
}: NewTermsFieldsEditProps): JSX.Element { | ||
return ( | ||
<UseField | ||
path={path} | ||
config={NEW_TERMS_FIELDS_CONFIG} | ||
component={NewTermsFieldsField} | ||
componentProps={{ fieldNames }} | ||
/> | ||
); | ||
}); | ||
|
||
const NEW_TERMS_FIELDS_CONFIG = { | ||
type: FIELD_TYPES.COMBO_BOX, | ||
label: i18n.translate( | ||
'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsFieldsLabel', | ||
{ | ||
defaultMessage: 'Fields', | ||
} | ||
), | ||
helpText: i18n.translate( | ||
'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.fieldNewTermsFieldHelpText', | ||
{ | ||
defaultMessage: 'Select a field to check for new terms.', | ||
} | ||
), | ||
validations: [ | ||
{ | ||
validator: ( | ||
...args: Parameters<ValidationFunc> | ||
): ReturnType<ValidationFunc<{}, ERROR_CODE>> | undefined => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Return type could be omitted. |
||
return newTermsFieldsValidatorFactory(...args); | ||
}, | ||
}, | ||
], | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,38 +5,36 @@ | |
* 2.0. | ||
*/ | ||
|
||
import React, { useMemo } from 'react'; | ||
import React from 'react'; | ||
|
||
import type { DataViewFieldBase } from '@kbn/es-query'; | ||
import type { FieldHook } from '../../../../shared_imports'; | ||
import { Field } from '../../../../shared_imports'; | ||
import { NEW_TERMS_FIELD_PLACEHOLDER } from './translations'; | ||
|
||
interface NewTermsFieldsProps { | ||
browserFields: DataViewFieldBase[]; | ||
fieldNames: DataViewFieldBase[]; | ||
field: FieldHook; | ||
} | ||
|
||
const FIELD_COMBO_BOX_WIDTH = 410; | ||
|
||
const fieldDescribedByIds = 'detectionEngineStepDefineRuleNewTermsField'; | ||
const fieldDescribedByIds = 'newTermsFieldEdit'; | ||
|
||
export const NewTermsFieldsComponent: React.FC<NewTermsFieldsProps> = ({ | ||
browserFields, | ||
const NewTermsFieldsEditFieldComponent: React.FC<NewTermsFieldsProps> = ({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The function could be defined simpler const NewTermsFieldsField = memo(function NewTermsFieldsField(): JSX.Element {
// ...
}); |
||
fieldNames, | ||
field, | ||
}: NewTermsFieldsProps) => { | ||
const fieldEuiFieldProps = useMemo( | ||
() => ({ | ||
fullWidth: true, | ||
noSuggestions: false, | ||
options: browserFields.map((browserField) => ({ label: browserField.name })), | ||
placeholder: NEW_TERMS_FIELD_PLACEHOLDER, | ||
onCreateOption: undefined, | ||
style: { width: `${FIELD_COMBO_BOX_WIDTH}px` }, | ||
}), | ||
[browserFields] | ||
); | ||
const fieldEuiFieldProps = { | ||
fullWidth: true, | ||
noSuggestions: false, | ||
options: fieldNames.map((name) => ({ label: name })), | ||
placeholder: NEW_TERMS_FIELD_PLACEHOLDER, | ||
onCreateOption: undefined, | ||
style: { width: `${FIELD_COMBO_BOX_WIDTH}px` }, | ||
}; | ||
|
||
return <Field field={field} idAria={fieldDescribedByIds} euiFieldProps={fieldEuiFieldProps} />; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It could use |
||
}; | ||
|
||
export const NewTermsFields = React.memo(NewTermsFieldsComponent); | ||
export const NewTermsFieldsField = React.memo(NewTermsFieldsEditFieldComponent); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
export { ScheduleItemField } from './schedule_item_field'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Translations could be moved to
translations.ts
.