diff --git a/x-pack/plugins/stack_connectors/public/connector_types/email/email_params.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/email/email_params.test.tsx
index 76cc3b136455a..3d772556e7262 100644
--- a/x-pack/plugins/stack_connectors/public/connector_types/email/email_params.test.tsx
+++ b/x-pack/plugins/stack_connectors/public/connector_types/email/email_params.test.tsx
@@ -7,12 +7,13 @@
import React from 'react';
import { mountWithIntl } from '@kbn/test-jest-helpers';
-import { render, fireEvent, screen } from '@testing-library/react';
+import { render, fireEvent, screen, within } from '@testing-library/react';
import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { triggersActionsUiMock } from '@kbn/triggers-actions-ui-plugin/public/mocks';
import EmailParamsFields from './email_params';
import { getIsExperimentalFeatureEnabled } from '../../common/get_experimental_features';
+import { getFormattedEmailOptions } from './email_params';
jest.mock('@kbn/kibana-react-plugin/public', () => ({
useKibana: jest.fn(),
@@ -28,6 +29,24 @@ const mockKibana = () => {
});
};
+const emailTestCases = [
+ {
+ field: 'to',
+ fieldValue: 'new1@test.com, new2@test.com , new1@test.com, ',
+ expected: ['test@test.com', 'new1@test.com', 'new2@test.com'],
+ },
+ {
+ field: 'cc',
+ fieldValue: 'newcc1@test.com, newcc2@test.com , newcc1@test.com, ',
+ expected: ['cc@test.com', 'newcc1@test.com', 'newcc2@test.com'],
+ },
+ {
+ field: 'bcc',
+ fieldValue: 'newbcc1@test.com, newbcc2@test.com , newbcc1@test.com, ',
+ expected: ['bcc@test.com', 'newbcc1@test.com', 'newbcc2@test.com'],
+ },
+];
+
describe('EmailParamsFields renders', () => {
beforeEach(() => {
jest.clearAllMocks();
@@ -62,6 +81,40 @@ describe('EmailParamsFields renders', () => {
expect(await screen.findByTestId('messageTextArea')).toBeVisible();
});
+ emailTestCases.forEach(({ field, fieldValue, expected }) => {
+ test(`"${field}" field value updates correctly when comma-separated emails are pasted`, async () => {
+ const actionParams = {
+ cc: ['cc@test.com'],
+ bcc: ['bcc@test.com'],
+ to: ['test@test.com'],
+ subject: 'test',
+ message: 'test message',
+ };
+
+ const editAction = jest.fn();
+
+ render(
+
+
+
+ );
+
+ const euiComboBox = screen.getByTestId(`${field}EmailAddressInput`);
+ const input = within(euiComboBox).getByTestId('comboBoxSearchInput');
+ fireEvent.change(input, { target: { value: fieldValue } });
+ expect(input).toHaveValue(fieldValue);
+
+ fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
+ expect(editAction).toHaveBeenCalledWith(field, expected, 0);
+ });
+ });
+
test('message param field is rendered with default value if not set', () => {
const actionParams = {
cc: [],
@@ -234,3 +287,48 @@ describe('EmailParamsFields renders', () => {
expect(editAction).not.toHaveBeenCalled();
});
});
+
+describe('getFormattedEmailOptions', () => {
+ test('should return new options added to previous options', () => {
+ const searchValue = 'test@test.com, other@test.com';
+ const previousOptions = [{ label: 'existing@test.com' }];
+ const newOptions = getFormattedEmailOptions(searchValue, previousOptions);
+
+ expect(newOptions).toEqual([
+ { label: 'existing@test.com' },
+ { label: 'test@test.com' },
+ { label: 'other@test.com' },
+ ]);
+ });
+
+ test('should trim extra spaces in search value', () => {
+ const searchValue = ' test@test.com , other@test.com , ';
+ const previousOptions: Array<{ label: string }> = [];
+ const newOptions = getFormattedEmailOptions(searchValue, previousOptions);
+
+ expect(newOptions).toEqual([{ label: 'test@test.com' }, { label: 'other@test.com' }]);
+ });
+
+ test('should prevent duplicate email addresses', () => {
+ const searchValue = 'duplicate@test.com, duplicate@test.com';
+ const previousOptions = [{ label: 'existing@test.com' }, { label: 'duplicate@test.com' }];
+ const newOptions = getFormattedEmailOptions(searchValue, previousOptions);
+
+ expect(newOptions).toEqual([{ label: 'existing@test.com' }, { label: 'duplicate@test.com' }]);
+ });
+
+ test('should return previous options if search value is empty', () => {
+ const searchValue = '';
+ const previousOptions = [{ label: 'existing@test.com' }];
+ const newOptions = getFormattedEmailOptions(searchValue, previousOptions);
+ expect(newOptions).toEqual([{ label: 'existing@test.com' }]);
+ });
+
+ test('should handle single email without comma', () => {
+ const searchValue = 'single@test.com';
+ const previousOptions = [{ label: 'existing@test.com' }];
+ const newOptions = getFormattedEmailOptions(searchValue, previousOptions);
+
+ expect(newOptions).toEqual([{ label: 'existing@test.com' }, { label: 'single@test.com' }]);
+ });
+});
diff --git a/x-pack/plugins/stack_connectors/public/connector_types/email/email_params.tsx b/x-pack/plugins/stack_connectors/public/connector_types/email/email_params.tsx
index d9a4750cb4564..745349ab5e872 100644
--- a/x-pack/plugins/stack_connectors/public/connector_types/email/email_params.tsx
+++ b/x-pack/plugins/stack_connectors/public/connector_types/email/email_params.tsx
@@ -18,6 +18,21 @@ import { EmailActionParams } from '../types';
const noop = () => {};
+export const getFormattedEmailOptions = (
+ searchValue: string,
+ previousOptions: Array<{ label: string }>
+): Array<{ label: string }> => {
+ if (!searchValue.trim()) return previousOptions;
+ const previousEmails: string[] = previousOptions.map((option) => option.label);
+ const allUniqueEmails: Set = new Set(previousEmails);
+ searchValue.split(',').forEach((email) => {
+ const trimmedEmail = email.trim();
+ if (trimmedEmail) allUniqueEmails.add(trimmedEmail);
+ });
+ const formattedOptions = Array.from(allUniqueEmails).map((email) => ({ label: email }));
+ return formattedOptions;
+};
+
export const EmailParamsFields = ({
actionParams,
editAction,
@@ -105,7 +120,7 @@ export const EmailParamsFields = ({
data-test-subj="toEmailAddressInput"
selectedOptions={toOptions}
onCreateOption={(searchValue: string) => {
- const newOptions = [...toOptions, { label: searchValue }];
+ const newOptions = getFormattedEmailOptions(searchValue, toOptions);
editAction(
'to',
newOptions.map((newOption) => newOption.label),
@@ -148,7 +163,7 @@ export const EmailParamsFields = ({
data-test-subj="ccEmailAddressInput"
selectedOptions={ccOptions}
onCreateOption={(searchValue: string) => {
- const newOptions = [...ccOptions, { label: searchValue }];
+ const newOptions = getFormattedEmailOptions(searchValue, ccOptions);
editAction(
'cc',
newOptions.map((newOption) => newOption.label),
@@ -192,7 +207,7 @@ export const EmailParamsFields = ({
data-test-subj="bccEmailAddressInput"
selectedOptions={bccOptions}
onCreateOption={(searchValue: string) => {
- const newOptions = [...bccOptions, { label: searchValue }];
+ const newOptions = getFormattedEmailOptions(searchValue, bccOptions);
editAction(
'bcc',
newOptions.map((newOption) => newOption.label),