diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/related_integrations/related_integrations.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/related_integrations/related_integrations.tsx
index 8b2442940771..abce17b21a03 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/related_integrations/related_integrations.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/related_integrations/related_integrations.tsx
@@ -8,55 +8,101 @@
import React from 'react';
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSpacer } from '@elastic/eui';
import { UseArray, useFormData } from '../../../../shared_imports';
+import type { FormHook, ArrayItem } from '../../../../shared_imports';
import { RelatedIntegrationsHelpInfo } from './related_integrations_help_info';
import { RelatedIntegrationFieldRow } from './related_integration_field_row';
import * as i18n from './translations';
import { OptionalFieldLabel } from '../optional_field_label';
+import { getFlattenedArrayFieldNames } from '../utils';
interface RelatedIntegrationsProps {
path: string;
dataTestSubj?: string;
}
-export function RelatedIntegrations({ path, dataTestSubj }: RelatedIntegrationsProps): JSX.Element {
+function RelatedIntegrationsComponent({
+ path,
+ dataTestSubj,
+}: RelatedIntegrationsProps): JSX.Element {
+ return (
+
+ {({ items, addItem, removeItem, form }) => (
+
+ )}
+
+ );
+}
+
+interface RelatedIntegrationsListProps {
+ items: ArrayItem[];
+ addItem: () => void;
+ removeItem: (id: number) => void;
+ path: string;
+ form: FormHook;
+ dataTestSubj?: string;
+}
+
+const RelatedIntegrationsList = ({
+ items,
+ addItem,
+ removeItem,
+ path,
+ form,
+ dataTestSubj,
+}: RelatedIntegrationsListProps) => {
+ const flattenedFieldNames = getFlattenedArrayFieldNames(form, path);
+
+ /*
+ Not using "watch" for the initial render, to let row components render and initialize form fields.
+ Then we can use the "watch" feature to track their changes.
+ */
+ const hasRenderedInitially = flattenedFieldNames.length > 0;
+ const fieldsToWatch = hasRenderedInitially ? flattenedFieldNames : [];
+
+ const [formData] = useFormData({ watch: fieldsToWatch });
+
const label = (
<>
{i18n.RELATED_INTEGRATIONS_LABEL}
>
);
- const [formData] = useFormData();
return (
-
- {({ items, addItem, removeItem }) => (
-
- <>
-
- {items.map((item) => (
-
-
-
- ))}
-
- {items.length > 0 && }
-
- {i18n.ADD_INTEGRATION}
-
- >
-
- )}
-
+
+ <>
+
+ {items.map((item) => (
+
+
+
+ ))}
+
+ {items.length > 0 && }
+
+ {i18n.ADD_INTEGRATION}
+
+ >
+
);
-}
+};
+
+export const RelatedIntegrations = React.memo(RelatedIntegrationsComponent);
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/make_validate_required_field.ts b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/make_validate_required_field.ts
index 26ddcc5f61c1..499f7fc60b2d 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/make_validate_required_field.ts
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/make_validate_required_field.ts
@@ -8,7 +8,7 @@
import type { RequiredFieldInput } from '../../../../../common/api/detection_engine/model/rule_schema/common_attributes.gen';
import type { ERROR_CODE, FormData, FormHook, ValidationFunc } from '../../../../shared_imports';
import * as i18n from './translations';
-import { getFlattenedArrayFieldNames } from './utils';
+import { getFlattenedArrayFieldNames } from '../utils';
export function makeValidateRequiredField(parentFieldPath: string) {
return function validateRequiredField(
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/required_fields.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/required_fields.tsx
index 27387909d330..9bfa9d45d1bb 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/required_fields.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/required_fields.tsx
@@ -16,7 +16,7 @@ import { RequiredFieldsHelpInfo } from './required_fields_help_info';
import * as defineRuleI18n from '../../../rule_creation_ui/components/step_define_rule/translations';
import { OptionalFieldLabel } from '../optional_field_label';
import { RequiredFieldRow } from './required_fields_row';
-import { getFlattenedArrayFieldNames } from './utils';
+import { getFlattenedArrayFieldNames } from '../utils';
import * as i18n from './translations';
interface RequiredFieldsComponentProps {
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/utils.ts b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/utils.ts
index 38820e992fa6..55beca264e12 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/utils.ts
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/utils.ts
@@ -5,8 +5,6 @@
* 2.0.
*/
-import type { FormHook, ArrayItem } from '../../../../shared_imports';
-
interface PickTypeForNameParameters {
name: string;
type: string;
@@ -28,26 +26,3 @@ export function pickTypeForName({ name, type, typesByFieldName = {} }: PickTypeF
*/
return typesAvailableForName[0] ?? type;
}
-
-/**
- * Returns a list of flattened field names for a given array field of a form.
- * Flattened field name is a string that represents the path to an item in an array field.
- * For example, a field "myArrayField" can be represented as "myArrayField[0]", "myArrayField[1]", etc.
- *
- * Flattened field names are useful:
- * - when you need to subscribe to changes in an array field using `useFormData` "watch" option
- * - when you need to retrieve form data before serializer function is applied
- *
- * @param {Object} form - Form object.
- * @param {string} arrayFieldName - Path to the array field.
- * @returns {string[]} - Flattened array field names.
- */
-export function getFlattenedArrayFieldNames(
- form: { getFields: FormHook['getFields'] },
- arrayFieldName: string
-): string[] {
- const internalField = form.getFields()[`${arrayFieldName}__array__`] ?? {};
- const internalFieldValue = (internalField?.value ?? []) as ArrayItem[];
-
- return internalFieldValue.map((item) => item.path);
-}
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/utils.ts b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/utils.ts
new file mode 100644
index 000000000000..79ea06bef38c
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/utils.ts
@@ -0,0 +1,31 @@
+/*
+ * 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 type { ArrayItem, FormHook } from '../../../shared_imports';
+
+/**
+ * Returns a list of flattened field names for a given array field of a form.
+ * Flattened field name is a string that represents the path to an item in an array field.
+ * For example, a field "myArrayField" can be represented as "myArrayField[0]", "myArrayField[1]", etc.
+ *
+ * Flattened field names are useful:
+ * - when you need to subscribe to changes in an array field using `useFormData` "watch" option
+ * - when you need to retrieve form data before serializer function is applied
+ *
+ * @param {Object} form - Form object.
+ * @param {string} arrayFieldName - Path to the array field.
+ * @returns {string[]} - Flattened array field names.
+ */
+export function getFlattenedArrayFieldNames(
+ form: { getFields: FormHook['getFields'] },
+ arrayFieldName: string
+): string[] {
+ const internalField = form.getFields()[`${arrayFieldName}__array__`] ?? {};
+ const internalFieldValue = (internalField?.value ?? []) as ArrayItem[];
+
+ return internalFieldValue.map((item) => item.path);
+}