Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
} from '@kbn/triggers-actions-ui-plugin/public';
import { EmailActionParams } from '../../types';

const noop = () => {};

export const EmailParamsFields = ({
actionParams,
editAction,
Expand All @@ -25,6 +27,7 @@ export const EmailParamsFields = ({
defaultMessage,
isLoading,
isDisabled,
onBlur = noop,
showEmailSubjectAndMessage = true,
}: ActionParamsProps<EmailActionParams>) => {
const { to, cc, bcc, subject, message } = actionParams;
Expand Down Expand Up @@ -114,6 +117,7 @@ export const EmailParamsFields = ({
if (!to) {
editAction('to', [], index);
}
onBlur('to');
}}
/>
</EuiFormRow>
Expand Down Expand Up @@ -156,6 +160,7 @@ export const EmailParamsFields = ({
if (!cc) {
editAction('cc', [], index);
}
onBlur('cc');
}}
/>
</EuiFormRow>
Expand Down Expand Up @@ -199,6 +204,7 @@ export const EmailParamsFields = ({
if (!bcc) {
editAction('bcc', [], index);
}
onBlur('bcc');
}}
/>
</EuiFormRow>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,9 @@ export const DYNAMIC_SETTINGS_DEFAULTS: DynamicSettings = {
certAgeThreshold: 730,
certExpirationThreshold: 30,
defaultConnectors: [],
defaultEmail: {
to: [],
cc: [],
bcc: [],
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* 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 { journey, step, expect, before, after } from '@elastic/synthetics';
import { byTestId } from '@kbn/observability-plugin/e2e/utils';
import { syntheticsAppPageProvider } from '../../page_objects/synthetics_app';
import { cleanSettings } from './services/settings';

journey('AlertingDefaults', async ({ page, params }) => {
const syntheticsApp = syntheticsAppPageProvider({ page, kibanaUrl: params.kibanaUrl });

page.setDefaultTimeout(60 * 1000);

before(async () => {
await cleanSettings(params);
});

after(async () => {
await cleanSettings(params);
});

step('Login to kibana', async () => {
await page.goto('http://localhost:5620/login?next=%2F');
await syntheticsApp.loginToKibana();
});

step('Go to Settings page', async () => {
await page.click('[aria-label="Toggle primary navigation"]');
await page.click('text=Synthetics');
await page.click('text=Settings');
});

step('Click text=Synthetics', async () => {
await page.click('text=Synthetics');
await page.click('text=Settings');
expect(page.url()).toBe('http://localhost:5620/app/synthetics/settings/alerting');
await page.click('.euiComboBox__inputWrap');
await page.click("text=There aren't any options available");
await page.click('button:has-text("Add connector")');
await page.click('p:has-text("Slack")');
await page.click('input[type="text"]');
await page.fill('input[type="text"]', 'Test slack');
await page.press('input[type="text"]', 'Tab');
});
step(
'Fill text=Webhook URLCreate a Slack Webhook URL(opens in a new tab or window) >> input[type="text"]',
async () => {
await page.fill(
'text=Webhook URLCreate a Slack Webhook URL(opens in a new tab or window) >> input[type="text"]',
'https://www.slack.com'
);
await page.click('button:has-text("Save")');
await page.click('.euiComboBox__inputWrap');
await page.click('button[role="option"]:has-text("Test slack")');
await page.click("text=You've selected all available options");
await page.click('button:has-text("Apply changes")');
await page.click('[aria-label="Remove Test slack from selection in this group"]');
await page.isDisabled('button:has-text("Discard changes")');
await page.click('button:has-text("Add connector")');
}
);
step('Click text=Email', async () => {
await page.click('text=Email');
await page.click('input[type="text"]');
await page.fill('input[type="text"]', 'Test email');
await page.press('input[type="text"]', 'Tab');
await page.selectOption('select', 'gmail');
await page.click('text=UsernamePassword >> input[type="text"]');
await page.fill('text=UsernamePassword >> input[type="text"]', 'elastic');
await page.press('text=UsernamePassword >> input[type="text"]', 'Tab');
await page.fill('input[type="password"]', 'changeme');
await page.click('button:has-text("Save")');
await page.click(
'text=Sender is required.Configure email accounts(opens in a new tab or window) >> input[type="text"]'
);
await page.fill(
'text=Sender is required.Configure email accounts(opens in a new tab or window) >> input[type="text"]',
'test@gmail.com'
);
await page.click('button:has-text("Save")');
});
step('Click .euiComboBox__inputWrap', async () => {
await page.click('.euiComboBox__inputWrap');
await page.click('button[role="option"]:has-text("Test email")');
await page.click(byTestId('toEmailAddressInput'));
await page.fill(
'text=To CcBccCombo box. Selected. Combo box input. Type some text or, to display a li >> input[role="combobox"]',
'test@gmail.com'
);
await page.keyboard.press('Enter');
await page.fill(
'text=test@gmail.comCombo box. Selected. test@gmail.com. Press Backspace to delete tes >> input[role="combobox"]',
'tesyt'
);
await page.keyboard.press('Enter');

await page.click('[aria-label="Remove tesyt from selection in this group"]');
await page.click('button:has-text("Cc")');
await page.click(byTestId('ccEmailAddressInput'));

await page.fill(`${byTestId('ccEmailAddressInput')} >> input[role="combobox"]`, 'wow');
await page.keyboard.press('Enter');
});
step('Click text=wow is not a valid email.', async () => {
await page.click('text=wow is not a valid email.');
await page.click('text=wowwow is not a valid email. >> [aria-label="Clear input"]');
await page.fill(`${byTestId('ccEmailAddressInput')} >> input[role="combobox"]`, 'list');
await page.click(
'text=Default emailEmail settings required for selected email alert connectors.To Bcct'
);
await page.click('[aria-label="Remove list from selection in this group"]');
await page.click(
'text=Default emailEmail settings required for selected email alert connectors.To Bcct'
);
await page.click('text=To Bcctest@gmail.com >> [aria-label="Clear input"]');
await page.click('.euiForm');
await page.click('text=To: Email is required for selected email connector');
});
step(
'Click .euiComboBox.euiComboBox--fullWidth.euiComboBox-isInvalid .euiFormControlLayout .euiFormControlLayout__childrenWrapper .euiComboBox__inputWrap',
async () => {
await page.click(
'.euiComboBox.euiComboBox--fullWidth.euiComboBox-isInvalid .euiFormControlLayout .euiFormControlLayout__childrenWrapper .euiComboBox__inputWrap'
);
await page.fill(
'text=To BccCombo box. Selected. Combo box input. Type some text or, to display a list >> input[role="combobox"]',
'test@gmail.com'
);
await page.isDisabled('button:has-text("Apply changes")');
await page.click('[aria-label="Account menu"]');
await page.click('text=Log out');
}
);

step('Login to kibana with readonly', async () => {
await syntheticsApp.loginToKibana('viewer', 'changeme');
});

step('Go to http://localhost:5620/app/synthetics/settings/alerting', async () => {
await page.goto('http://localhost:5620/app/synthetics/settings/alerting', {
waitUntil: 'networkidle',
});
await page.isDisabled('.euiComboBox__inputWrap');
await page.isDisabled('button:has-text("Apply changes")');
await page.isDisabled('button:has-text("Add connector")');
});
});
1 change: 1 addition & 0 deletions x-pack/plugins/synthetics/e2e/journeys/synthetics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export * from './overview_sorting.journey';
export * from './overview_scrolling.journey';
export * from './overview_search.journey';
export * from './private_locations.journey';
export * from './alerting_default.journey';
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,8 @@ export const cleanPrivateLocations = async (params: Record<string, any>) => {
const server = getService('kibanaServer');

try {
await server.savedObjects.clean({ types: [privateLocationsSavedObjectName] });
await server.savedObjects.clean({
types: ['ingest-agent-policies', 'ingest-package-policies'],
types: [privateLocationsSavedObjectName, 'ingest-agent-policies', 'ingest-package-policies'],
});
} catch (e) {
// eslint-disable-next-line no-console
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
*/

export const cleanSettings = async (params: Record<string, any>) => {
const getService = params.getService;
const server = getService('kibanaServer');

try {
await server.savedObjects.clean({ types: ['uptime-dynamic-settings'] });
await cleanConnectors(params);
} catch (e) {
// eslint-disable-next-line no-console
console.log(e);
}
};

export const cleanConnectors = async (params: Record<string, any>) => {
const getService = params.getService;
const server = getService('kibanaServer');

try {
const { data } = await server.requester.request({
path: '/api/actions/connectors',
method: 'GET',
});

for (const connector of data) {
await server.requester.request({
path: `/api/actions/connector/${connector.id}`,
method: 'DELETE',
});
}
} catch (e) {
// eslint-disable-next-line no-console
console.log(e);
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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, { useMemo, useState } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { useDispatch } from 'react-redux';
import { EuiButtonEmpty } from '@elastic/eui';
import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { getConnectorsAction } from '../../../state/settings/actions';

interface Props {
focusInput: () => void;
isDisabled: boolean;
}

interface KibanaDeps {
triggersActionsUi: TriggersAndActionsUIPublicPluginStart;
}

export const AddConnectorFlyout = ({ focusInput, isDisabled }: Props) => {
const [addFlyoutVisible, setAddFlyoutVisibility] = useState<boolean>(false);
const {
services: {
application,
triggersActionsUi: { getAddConnectorFlyout },
},
} = useKibana<KibanaDeps>();

const canEdit: boolean = !!application?.capabilities.actions.save;

const dispatch = useDispatch();

const ConnectorAddFlyout = useMemo(
() =>
getAddConnectorFlyout({
onClose: () => {
dispatch(getConnectorsAction.get());
setAddFlyoutVisibility(false);
focusInput();
},
featureId: 'uptime',
}),
[dispatch, focusInput, getAddConnectorFlyout]
);

return (
<>
{addFlyoutVisible ? ConnectorAddFlyout : null}
<EuiButtonEmpty
data-test-subj="createConnectorButton"
onClick={() => setAddFlyoutVisibility(true)}
size="s"
isDisabled={isDisabled || !canEdit}
>
<FormattedMessage
id="xpack.synthetics.alerts.settings.addConnector"
defaultMessage="Add connector"
/>
</EuiButtonEmpty>
</>
);
};
Loading