diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx
index 0cb7ce3982868..95987bdf19b69 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx
@@ -7,16 +7,62 @@
import React from 'react';
import { FieldFormWrapper } from './field_form_wrapper';
-import { NameEdit, nameSchema } from './fields/name';
import type { UpgradeableCommonFields } from '../../../../model/prebuilt_rule_upgrade/fields';
+import { DescriptionEdit, descriptionSchema } from './fields/description';
+import {
+ FalsePositivesEdit,
+ falsePositivesSchema,
+ falsePositivesSerializer,
+ falsePositivesDeserializer,
+} from './fields/false_positives';
+import {
+ InvestigationFieldsEdit,
+ investigationFieldsSchema,
+ investigationFieldsDeserializer,
+ investigationFieldsSerializer,
+} from './fields/investigation_fields';
+import { NameEdit, nameSchema } from './fields/name';
+import { ReferencesEdit, referencesSchema, referencesSerializer } from './fields/references';
+import { TagsEdit, tagsSchema } from './fields/tags';
+
interface CommonRuleFieldEditProps {
fieldName: UpgradeableCommonFields;
}
export function CommonRuleFieldEdit({ fieldName }: CommonRuleFieldEditProps) {
switch (fieldName) {
+ case 'description':
+ return ;
+ case 'false_positives':
+ return (
+
+ );
+ case 'investigation_fields':
+ return (
+
+ );
case 'name':
return ;
+ case 'references':
+ return (
+
+ );
+ case 'tags':
+ return ;
default:
return null; // Will be replaced with `assertUnreachable(fieldName)` once all fields are implemented
}
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/description.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/description.tsx
new file mode 100644
index 0000000000000..c2d279c0d72e2
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/description.tsx
@@ -0,0 +1,27 @@
+/*
+ * 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 type { FormSchema } from '../../../../../../../shared_imports';
+import { Field, UseField } from '../../../../../../../shared_imports';
+import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema';
+import type { RuleDescription } from '../../../../../../../../common/api/detection_engine';
+
+export const descriptionSchema = { description: schema.description } as FormSchema<{
+ description: RuleDescription;
+}>;
+
+const componentProps = {
+ euiFieldProps: {
+ fullWidth: true,
+ compressed: true,
+ },
+};
+
+export function DescriptionEdit(): JSX.Element {
+ return ;
+}
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/false_positives.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/false_positives.tsx
new file mode 100644
index 0000000000000..25f38e03dfa80
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/false_positives.tsx
@@ -0,0 +1,43 @@
+/*
+ * 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 { compact } from 'lodash';
+import * as i18n from '../../../../../../rule_creation_ui/components/step_about_rule/translations';
+import type { FormSchema, FormData } from '../../../../../../../shared_imports';
+import { UseField } from '../../../../../../../shared_imports';
+import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema';
+import type { RuleFalsePositiveArray } from '../../../../../../../../common/api/detection_engine';
+import { AddItem } from '../../../../../../rule_creation_ui/components/add_item_form';
+
+export const falsePositivesSchema = { falsePositives: schema.falsePositives } as FormSchema<{
+ falsePositives: RuleFalsePositiveArray;
+}>;
+
+const componentProps = {
+ addText: i18n.ADD_FALSE_POSITIVE,
+};
+
+export function FalsePositivesEdit(): JSX.Element {
+ return ;
+}
+
+export function falsePositivesDeserializer(defaultValue: FormData) {
+ /* Set initial form value with camelCase "falsePositives" key instead of "false_positives" */
+ return {
+ falsePositives: defaultValue,
+ };
+}
+
+export function falsePositivesSerializer(formData: FormData): {
+ false_positives: RuleFalsePositiveArray;
+} {
+ return {
+ /* Remove empty items from the falsePositives array */
+ false_positives: compact(formData.falsePositives),
+ };
+}
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/investigation_fields.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/investigation_fields.tsx
new file mode 100644
index 0000000000000..39c0c75d965a0
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/investigation_fields.tsx
@@ -0,0 +1,83 @@
+/*
+ * 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 type { FormSchema, FormData } from '../../../../../../../shared_imports';
+import { UseField } from '../../../../../../../shared_imports';
+import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema';
+import type {
+ DiffableRule,
+ InvestigationFields,
+ RuleFalsePositiveArray,
+} from '../../../../../../../../common/api/detection_engine';
+import { MultiSelectFieldsAutocomplete } from '../../../../../../rule_creation_ui/components/multi_select_fields';
+import { useAllEsqlRuleFields } from '../../../../../../rule_creation_ui/hooks';
+import { useDefaultIndexPattern } from '../../../use_default_index_pattern';
+import { useRuleIndexPattern } from '../../../../../../rule_creation_ui/pages/form';
+import { getUseRuleIndexPatternParameters } from '../utils';
+
+export const investigationFieldsSchema = {
+ investigationFields: schema.investigationFields,
+} as FormSchema<{
+ investigationFields: RuleFalsePositiveArray;
+}>;
+
+interface InvestigationFieldsEditProps {
+ finalDiffableRule: DiffableRule;
+}
+
+export function InvestigationFieldsEdit({
+ finalDiffableRule,
+}: InvestigationFieldsEditProps): JSX.Element {
+ const { type } = finalDiffableRule;
+
+ const defaultIndexPattern = useDefaultIndexPattern();
+ const indexPatternParameters = getUseRuleIndexPatternParameters(
+ finalDiffableRule,
+ defaultIndexPattern
+ );
+ const { indexPattern, isIndexPatternLoading } = useRuleIndexPattern(indexPatternParameters);
+
+ const { fields: investigationFields, isLoading: isInvestigationFieldsLoading } =
+ useAllEsqlRuleFields({
+ esqlQuery: type === 'esql' ? finalDiffableRule.esql_query.query : undefined,
+ indexPatternsFields: indexPattern.fields,
+ });
+
+ return (
+
+ );
+}
+
+export function investigationFieldsDeserializer(defaultValue: FormData) {
+ /* Set initial form value with camelCase "investigationFields" key instead of "investigation_fields" */
+ return {
+ investigationFields: defaultValue?.field_names ?? [],
+ };
+}
+
+export function investigationFieldsSerializer(formData: FormData): {
+ investigation_fields: InvestigationFields | undefined;
+} {
+ const hasInvestigationFields = formData.investigationFields.length > 0;
+
+ return {
+ investigation_fields: hasInvestigationFields
+ ? {
+ field_names: formData.investigationFields,
+ }
+ : undefined,
+ };
+}
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query.tsx
index 69a00436b6992..c644dbdc74dcb 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query.tsx
@@ -18,7 +18,6 @@ import type { FieldValueQueryBar } from '../../../../../../rule_creation_ui/comp
import * as stepDefineRuleI18n from '../../../../../../rule_creation_ui/components/step_define_rule/translations';
import { useRuleIndexPattern } from '../../../../../../rule_creation_ui/pages/form';
import {
- DataSourceType as DataSourceTypeSnakeCase,
KqlQueryLanguage,
KqlQueryType,
RuleQuery,
@@ -32,11 +31,11 @@ import type {
SavedKqlQuery,
} from '../../../../../../../../common/api/detection_engine';
import { useDefaultIndexPattern } from '../../../use_default_index_pattern';
-import { DataSourceType } from '../../../../../../../detections/pages/detection_engine/rules/types';
import { isFilters } from '../../../helpers';
import type { SetRuleQuery } from '../../../../../../../detections/containers/detection_engine/rules/use_rule_from_timeline';
import { useRuleFromTimeline } from '../../../../../../../detections/containers/detection_engine/rules/use_rule_from_timeline';
import { useGetSavedQuery } from '../../../../../../../detections/pages/detection_engine/rules/use_get_saved_query';
+import { getUseRuleIndexPatternParameters } from '../utils';
export const kqlQuerySchema = {
ruleType: schema.ruleType,
@@ -199,37 +198,6 @@ export function kqlQueryDeserializer(
return returnValue;
}
-interface UseRuleIndexPatternParameters {
- dataSourceType: DataSourceType;
- index: string[];
- dataViewId: string | undefined;
-}
-
-function getUseRuleIndexPatternParameters(
- finalDiffableRule: DiffableRule,
- defaultIndexPattern: string[]
-): UseRuleIndexPatternParameters {
- if (!('data_source' in finalDiffableRule) || !finalDiffableRule.data_source) {
- return {
- dataSourceType: DataSourceType.IndexPatterns,
- index: defaultIndexPattern,
- dataViewId: undefined,
- };
- }
- if (finalDiffableRule.data_source.type === DataSourceTypeSnakeCase.data_view) {
- return {
- dataSourceType: DataSourceType.DataView,
- index: [],
- dataViewId: finalDiffableRule.data_source.data_view_id,
- };
- }
- return {
- dataSourceType: DataSourceType.IndexPatterns,
- index: finalDiffableRule.data_source.index_patterns,
- dataViewId: undefined,
- };
-}
-
function getSavedQueryId(diffableRule: DiffableRule): string | undefined {
if (diffableRule.type === 'saved_query' && 'saved_query_id' in diffableRule.kql_query) {
return diffableRule.kql_query.saved_query_id;
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/name.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/name.tsx
index 10ae6cffbe50d..d602da90f34b0 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/name.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/name.tsx
@@ -13,16 +13,12 @@ import type { RuleName } from '../../../../../../../../common/api/detection_engi
export const nameSchema = { name: schema.name } as FormSchema<{ name: RuleName }>;
+const componentProps = {
+ euiFieldProps: {
+ fullWidth: true,
+ },
+};
+
export function NameEdit(): JSX.Element {
- return (
-
- );
+ return ;
}
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/references.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/references.tsx
new file mode 100644
index 0000000000000..afa4fba09d890
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/references.tsx
@@ -0,0 +1,38 @@
+/*
+ * 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 { compact } from 'lodash';
+import * as i18n from '../../../../../../rule_creation_ui/components/step_about_rule/translations';
+import type { FormSchema, FormData } from '../../../../../../../shared_imports';
+import { UseField } from '../../../../../../../shared_imports';
+import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema';
+import type { RuleReferenceArray } from '../../../../../../../../common/api/detection_engine';
+import { AddItem } from '../../../../../../rule_creation_ui/components/add_item_form';
+import { isUrlInvalid } from '../../../../../../../common/utils/validators';
+
+export const referencesSchema = { references: schema.references } as FormSchema<{
+ references: RuleReferenceArray;
+}>;
+
+const componentProps = {
+ addText: i18n.ADD_REFERENCE,
+ validate: isUrlInvalid,
+};
+
+export function ReferencesEdit(): JSX.Element {
+ return ;
+}
+
+export function referencesSerializer(formData: FormData): {
+ references: RuleReferenceArray;
+} {
+ return {
+ /* Remove empty items from the references array */
+ references: compact(formData.references),
+ };
+}
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/tags.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/tags.tsx
new file mode 100644
index 0000000000000..78d7129498882
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/tags.tsx
@@ -0,0 +1,25 @@
+/*
+ * 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 type { FormSchema } from '../../../../../../../shared_imports';
+import { Field, UseField } from '../../../../../../../shared_imports';
+import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema';
+import type { RuleTagArray } from '../../../../../../../../common/api/detection_engine';
+
+export const tagsSchema = { tags: schema.tags } as FormSchema<{ tags: RuleTagArray }>;
+
+const componentProps = {
+ euiFieldProps: {
+ fullWidth: true,
+ placeholder: '',
+ },
+};
+
+export function TagsEdit(): JSX.Element {
+ return ;
+}
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/utils.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/utils.ts
new file mode 100644
index 0000000000000..bd78bb5e9ed26
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/utils.ts
@@ -0,0 +1,41 @@
+/*
+ * 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 { DataSourceType } from '../../../../../../detections/pages/detection_engine/rules/types';
+import { DataSourceType as DataSourceTypeSnakeCase } from '../../../../../../../common/api/detection_engine';
+import type { DiffableRule } from '../../../../../../../common/api/detection_engine';
+
+interface UseRuleIndexPatternParameters {
+ dataSourceType: DataSourceType;
+ index: string[];
+ dataViewId: string | undefined;
+}
+
+export function getUseRuleIndexPatternParameters(
+ finalDiffableRule: DiffableRule,
+ defaultIndexPattern: string[]
+): UseRuleIndexPatternParameters {
+ if (!('data_source' in finalDiffableRule) || !finalDiffableRule.data_source) {
+ return {
+ dataSourceType: DataSourceType.IndexPatterns,
+ index: defaultIndexPattern,
+ dataViewId: undefined,
+ };
+ }
+ if (finalDiffableRule.data_source.type === DataSourceTypeSnakeCase.data_view) {
+ return {
+ dataSourceType: DataSourceType.DataView,
+ index: [],
+ dataViewId: finalDiffableRule.data_source.data_view_id,
+ };
+ }
+ return {
+ dataSourceType: DataSourceType.IndexPatterns,
+ index: finalDiffableRule.data_source.index_patterns,
+ dataViewId: undefined,
+ };
+}
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/false_positives/false_positives.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/false_positives/false_positives.tsx
index f026609b6c850..7480af5dff4c5 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/false_positives/false_positives.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/false_positives/false_positives.tsx
@@ -16,6 +16,10 @@ interface FalsePositivesReadOnlyProps {
}
export function FalsePositivesReadOnly({ falsePositives }: FalsePositivesReadOnlyProps) {
+ if (falsePositives.length === 0) {
+ return null;
+ }
+
return (