Email plugin DS migration

This commit is contained in:
ronronscelestes 2021-09-13 17:08:41 +02:00
parent 7cd1719385
commit c343bab43a
9 changed files with 1277 additions and 200 deletions

View File

@ -5,14 +5,14 @@ import i18nPlugin from '../../../../plugins/i18n/admin/src';
// import sentryPlugin from '../../../../plugins/sentry/admin/src'; // import sentryPlugin from '../../../../plugins/sentry/admin/src';
import usersPermissionsPlugin from '../../../../plugins/users-permissions/admin/src'; import usersPermissionsPlugin from '../../../../plugins/users-permissions/admin/src';
import ctbPlugin from '../../../content-type-builder/admin/src'; import ctbPlugin from '../../../content-type-builder/admin/src';
// import emailPlugin from '../../../email/admin/src'; import emailPlugin from '../../../email/admin/src';
import uploadPlugin from '../../../upload/admin/src'; import uploadPlugin from '../../../upload/admin/src';
const plugins = { const plugins = {
'@strapi/plugin-content-type-builder': ctbPlugin, '@strapi/plugin-content-type-builder': ctbPlugin,
// '@strapi/plugin-documentation': documentationPlugin, // '@strapi/plugin-documentation': documentationPlugin,
'@strapi/plugin-i18n': i18nPlugin, '@strapi/plugin-i18n': i18nPlugin,
// '@strapi/plugin-email': emailPlugin, '@strapi/plugin-email': emailPlugin,
'@strapi/plugin-upload': uploadPlugin, '@strapi/plugin-upload': uploadPlugin,
// '@strapi/plugin-graphql': graphqlPlugin, // '@strapi/plugin-graphql': graphqlPlugin,
// '@strapi/plugin-sentry': sentryPlugin, // '@strapi/plugin-sentry': sentryPlugin,

View File

@ -1,16 +0,0 @@
import styled from 'styled-components';
import { Button, Text as TextBase } from '@buffetjs/core';
const Text = styled(TextBase)`
width: 100%;
padding: 0 15px 17px 15px;
`;
const AlignedButton = styled(Button)`
height: 34px;
padding-top: 3px;
margin: 29px 15px 0 15px;
min-width: unset;
`;
export { Text, AlignedButton };

View File

@ -0,0 +1,108 @@
/* eslint-disable no-useless-escape */
import React from 'react';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { Stack } from '@strapi/parts/Stack';
import { Grid, GridItem } from '@strapi/parts/Grid';
import { H3, Text } from '@strapi/parts/Text';
import { TextInput } from '@strapi/parts/TextInput';
import { Select, Option } from '@strapi/parts/Select';
import getTrad from '../../../utils/getTrad';
const Configuration = ({ config }) => {
const { formatMessage } = useIntl();
return (
<Stack size={4}>
<Stack size={1}>
<H3 as="h2">
{formatMessage({
id: getTrad('Settings.email.plugin.title.config'),
defaultMessage: 'Configuration',
})}
</H3>
<Text>
{formatMessage(
{
id: getTrad('Settings.email.plugin.text.configuration'),
defaultMessage: 'Configuration',
},
{
file: './config/plugins.js',
link: (
<a
href="https://strapi.io/documentation/developer-docs/latest/development/plugins/email.html#configure-the-plugin"
target="_blank"
rel="noopener noreferrer"
>
link
</a>
),
}
)}
</Text>
</Stack>
<Grid gap={5}>
<GridItem col={6} s={12}>
<TextInput
name="shipper-email"
label={formatMessage({
id: getTrad('Settings.email.plugin.label.defaultFrom'),
defaultMessage: 'Default shipper email',
})}
placeholder={formatMessage({
id: getTrad('Settings.email.plugin.placeholder.defaultFrom'),
defaultMessage: `ex: Strapi No-Reply \<no-reply@strapi.io\>`,
})}
disabled
onChange={() => {}}
value={config.settings.defaultFrom}
/>
</GridItem>
<GridItem col={6} s={12}>
<TextInput
name="response-email"
label={formatMessage({
id: getTrad('Settings.email.plugin.label.defaultReplyTo'),
defaultMessage: 'Default response email',
})}
placeholder={formatMessage({
id: getTrad('Settings.email.plugin.placeholder.defaultReplyTo'),
defaultMessage: `ex: Strapi \<example@strapi.io\>`,
})}
disabled
onChange={() => {}}
value={config.settings.defaultReplyTo}
/>
</GridItem>
<GridItem col={6} s={12}>
<Select
name="email-provider"
label={formatMessage({
id: getTrad('Settings.email.plugin.label.provider'),
defaultMessage: 'Email provider',
})}
disabled
onChange={() => {}}
value={config.provider}
>
<Option value={config.provider}>{config.provider}</Option>
</Select>
</GridItem>
</Grid>
</Stack>
);
};
Configuration.propTypes = {
config: PropTypes.shape({
provider: PropTypes.string,
settings: PropTypes.shape({
defaultFrom: PropTypes.string,
defaultReplyTo: PropTypes.string,
}),
}).isRequired,
};
export default Configuration;

View File

@ -0,0 +1,33 @@
import React from 'react';
import { useIntl } from 'react-intl';
import { SettingsPageTitle } from '@strapi/helper-plugin';
import { HeaderLayout } from '@strapi/parts/Layout';
import getTrad from '../../../utils/getTrad';
const EmailHeader = () => {
const { formatMessage } = useIntl();
return (
<>
<SettingsPageTitle
name={formatMessage({
id: getTrad('Settings.email.plugin.title'),
defaultMessage: 'Email settings',
})}
/>
<HeaderLayout
id="title"
title={formatMessage({
id: getTrad('Settings.email.plugin.title'),
defaultMessage: 'Email settings',
})}
subtitle={formatMessage({
id: getTrad('Settings.email.plugin.subTitle'),
defaultMessage: 'Test the settings for the email plugin',
})}
/>
</>
);
};
export default EmailHeader;

View File

@ -1,23 +1,29 @@
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect } from 'react';
import { useIntl, FormattedMessage } from 'react-intl'; import { useIntl } from 'react-intl';
import { get } from 'lodash'; import { get } from 'lodash';
import { Header } from '@buffetjs/custom';
import { Envelope } from '@buffetjs/icons';
import { colors } from '@buffetjs/styles';
import { import {
FormBloc,
request,
SettingsPageTitle,
SizedInput,
getYupInnerErrors, getYupInnerErrors,
BaselineAlignment,
CheckPagePermissions, CheckPagePermissions,
useNotification, useNotification,
LoadingIndicatorPage,
useOverlayBlocker,
useFocusWhenNavigate,
} from '@strapi/helper-plugin'; } from '@strapi/helper-plugin';
import getTrad from '../../utils/getTrad'; import { Main } from '@strapi/parts/Main';
import { AlignedButton, Text } from './components'; import { ContentLayout } from '@strapi/parts/Layout';
import { Stack } from '@strapi/parts/Stack';
import { Box } from '@strapi/parts/Box';
import { Grid, GridItem } from '@strapi/parts/Grid';
import { H3 } from '@strapi/parts/Text';
import { TextInput } from '@strapi/parts/TextInput';
import { Button } from '@strapi/parts/Button';
import CheckIcon from '@strapi/icons/CheckIcon';
import Configuration from './components/Configuration';
import schema from '../../utils/schema'; import schema from '../../utils/schema';
import pluginPermissions from '../../permissions'; import pluginPermissions from '../../permissions';
import { fetchEmailSettings, postEmailTest } from './utils/api';
import EmailHeader from './components/EmailHeader';
import getTrad from '../../utils/getTrad';
const ProtectedSettingsPage = () => ( const ProtectedSettingsPage = () => (
<CheckPagePermissions permissions={pluginPermissions.settings}> <CheckPagePermissions permissions={pluginPermissions.settings}>
@ -28,185 +34,170 @@ const ProtectedSettingsPage = () => (
const SettingsPage = () => { const SettingsPage = () => {
const toggleNotification = useNotification(); const toggleNotification = useNotification();
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const { lockApp, unlockApp } = useOverlayBlocker();
useFocusWhenNavigate();
const [formErrors, setFormErrors] = useState({}); const [formErrors, setFormErrors] = useState({});
const [isTestButtonLoading, setIsTestButtonLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [showLoader, setShowLoader] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
const [testAddress, setTestAddress] = useState('');
const [config, setConfig] = useState({ const [config, setConfig] = useState({
provider: '', provider: '',
settings: { defaultFrom: '', defaultReplyTo: '', testAddress: '' }, settings: { defaultFrom: '', defaultReplyTo: '', testAddress: '' },
}); });
const [providers, setProviders] = useState([]);
const [testAddress, setTestAddress] = useState();
const [testSuccess, setTestSuccess] = useState(false);
const isMounted = useRef(true);
const title = formatMessage({ id: getTrad('Settings.title') }); const handleChange = e => {
setTestAddress(() => e.target.value);
};
const handleSubmit = async event => { const handleSubmit = async event => {
event.preventDefault(); event.preventDefault();
let errors = {};
try { try {
await schema.validate({ email: testAddress }, { abortEarly: false }); await schema.validate({ email: testAddress }, { abortEarly: false });
try { setIsSubmitting(true);
setIsTestButtonLoading(true); lockApp();
await request('/email/test', { postEmailTest({ to: testAddress })
method: 'POST', .then(() => {
body: { to: testAddress }, toggleNotification({
type: 'success',
message: formatMessage(
{
id: getTrad('Settings.email.plugin.notification.test.success'),
defaultMessage: 'Email test succeeded, check the {to} mailbox',
},
{ to: testAddress }
),
}); });
})
setTestSuccess(true); .catch(() => {
const message = formatMessage( toggleNotification({
{ id: getTrad('Settings.notification.test.success') }, type: 'warning',
message: formatMessage(
{
id: getTrad('Settings.email.plugin.notification.test.error'),
defaultMessage: 'Failed to send a test mail to {to}',
},
{ to: testAddress } { to: testAddress }
); ),
toggleNotification({ type: 'success', message }); });
} catch (err) { })
const message = formatMessage( .finally(() => {
{ id: getTrad('Settings.notification.test.error') }, setIsSubmitting(false);
{ to: testAddress } unlockApp();
); });
toggleNotification({ type: 'warning', message });
} finally {
if (isMounted.current) {
setIsTestButtonLoading(false);
}
}
} catch (error) { } catch (error) {
errors = getYupInnerErrors(error); setFormErrors(getYupInnerErrors(error));
setFormErrors(errors);
console.log(errors);
} }
}; };
useEffect(() => { useEffect(() => {
const fetchEmailSettings = () => { setIsLoading(true);
setShowLoader(true);
request('/email/settings', { fetchEmailSettings()
method: 'GET', .then(config => {
}) setConfig(config);
.then(data => {
setConfig(data.config); const testAddressFound = get(config, 'settings.testAddress');
setProviders([data.config.provider]);
setTestAddress(get(data, 'config.settings.testAddress')); if (testAddressFound) {
setTestAddress(testAddressFound);
}
}) })
.catch(() => .catch(() =>
toggleNotification({ toggleNotification({
type: 'warning', type: 'warning',
message: { id: getTrad('Settings.notification.config.error') }, message: formatMessage({
id: getTrad('Settings.email.plugin.notification.config.error'),
defaultMessage: 'Failed to retrieve the email config',
}),
}) })
) )
.finally(() => setShowLoader(false)); .finally(() => setIsLoading(false));
};
fetchEmailSettings();
}, [formatMessage, toggleNotification]); }, [formatMessage, toggleNotification]);
useEffect(() => { if (isLoading) {
return () => { return (
isMounted.current = false; <Main labelledBy="title" aria-busy="true">
}; <EmailHeader />
}, []); <ContentLayout>
<LoadingIndicatorPage />
</ContentLayout>
</Main>
);
}
return ( return (
<> <Main labelledBy="title" aria-busy={isSubmitting}>
<CheckPagePermissions permissions={pluginPermissions.settings}> <EmailHeader />
<SettingsPageTitle name={title} /> <ContentLayout>
<div>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<Header <Stack size={7}>
title={{ label: title }} <Box
content={formatMessage({ id: getTrad('Settings.subTitle') })} background="neutral0"
isLoading={showLoader} hasRadius
/> shadow="filterShadow"
<BaselineAlignment top size="3px" /> paddingTop={6}
<FormBloc paddingBottom={6}
title={formatMessage({ id: getTrad('Settings.form.title.config') })} paddingLeft={7}
isLoading={showLoader} paddingRight={7}
> >
<Text fontSize="md" lineHeight="18px"> <Configuration config={config} />
<FormattedMessage </Box>
id={getTrad('Settings.form.text.configuration')} <Box
values={{ background="neutral0"
file: <code>./config/plugins.js</code>, hasRadius
link: ( shadow="filterShadow"
<a paddingTop={6}
href="https://strapi.io/documentation/developer-docs/latest/development/plugins/email.html#configure-the-plugin" paddingBottom={6}
target="_blank" paddingLeft={7}
rel="noopener noreferrer" paddingRight={7}
> >
link <Stack size={4}>
</a> <H3 as="h2">
), {formatMessage({
}} id: getTrad('Settings.email.plugin.title.test'),
/> defaultMessage: 'Send a test mail',
</Text> })}
<SizedInput </H3>
disabled <Grid gap={5} alignItems="end">
label={getTrad('Settings.form.label.defaultFrom')} <GridItem col={6} s={12}>
name="default-from" <TextInput
placeholder={getTrad('Settings.form.placeholder.defaultFrom')}
size={{ xs: 6 }}
type="email"
value={config.settings.defaultFrom}
/>
<SizedInput
disabled
label={getTrad('Settings.form.label.defaultReplyTo')}
name="default-reply-to"
placeholder={getTrad('Settings.form.placeholder.defaultReplyTo')}
size={{ xs: 6 }}
type="email"
value={config.settings.defaultReplyTo}
/>
<SizedInput
disabled
label={getTrad('Settings.form.label.provider')}
name="provider"
options={providers}
size={{ xs: 6 }}
type="select"
value={`@strapi/provider-email-${config.provider}`}
/>
</FormBloc>
<BaselineAlignment top size="32px" />
<FormBloc
title={formatMessage({ id: getTrad('Settings.form.title.test') })}
isLoading={showLoader}
>
<SizedInput
label={getTrad('Settings.form.label.testAddress')}
name="test-address" name="test-address"
placeholder={getTrad('Settings.form.placeholder.testAddress')} onChange={handleChange}
onChange={event => setTestAddress(event.target.value)} label={formatMessage({
size={{ xs: 6 }} id: getTrad('Settings.email.plugin.label.testAddress'),
type="email" defaultMessage: 'Test delivery email address',
})}
value={testAddress} value={testAddress}
error={formErrors.email} error={
/> formErrors.email?.id &&
<AlignedButton formatMessage({
color="success" id: getTrad(`${formErrors.email?.id}`),
disabled={testSuccess} defaultMessage: 'An error occured',
icon={ })
<Envelope
fill={testSuccess ? colors.button.disabled.color : null}
style={{ verticalAlign: 'middle', marginRight: '10px' }}
/>
} }
isLoading={isTestButtonLoading} placeholder={formatMessage({
style={{ fontWeight: 600 }} id: 'Settings.email.plugin.placeholder.testAddress',
type="submit" defaultMessage: 'ex: developer@example.com',
> })}
{formatMessage({ id: getTrad('Settings.button.test-email') })} />
</AlignedButton> </GridItem>
</FormBloc> <GridItem col={7} s={12}>
{/* to replace with envelope icon */}
<Button loading={isSubmitting} type="submit" startIcon={<CheckIcon />}>
Test email
</Button>
</GridItem>
</Grid>
</Stack>
</Box>
</Stack>
</form> </form>
</div> </ContentLayout>
</CheckPagePermissions> </Main>
</>
); );
}; };

View File

@ -0,0 +1,931 @@
import React from 'react';
import { render, waitFor, screen } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import { ThemeProvider, lightTheme } from '@strapi/parts';
import server from './utils/server';
import ProtectedSettingsPage from '../index';
jest.mock('@strapi/helper-plugin', () => ({
...jest.requireActual('@strapi/helper-plugin'),
useNotification: jest.fn(),
useFocusWhenNavigate: jest.fn(),
CheckPagePermissions: ({ children }) => children,
useOverlayBlocker: jest.fn(() => ({
lockApp: jest.fn(),
unlockApp: jest.fn(),
})),
}));
const App = (
<IntlProvider locale="en" messages={{ en: {} }} textComponent="span">
<ThemeProvider theme={lightTheme}>
<ProtectedSettingsPage />
</ThemeProvider>
</IntlProvider>
);
describe('Email | Pages | Settings', () => {
beforeAll(() => server.listen());
beforeEach(() => {
jest.clearAllMocks();
});
afterEach(() => server.resetHandlers());
afterAll(() => {
server.close();
jest.resetAllMocks();
});
it('renders and matches the snapshot', async () => {
const { container } = render(App);
await waitFor(() => {
expect(screen.getByText('Test delivery email address')).toBeInTheDocument();
});
expect(container.firstChild).toMatchInlineSnapshot(`
.c42 {
font-weight: 500;
font-size: 0.75rem;
line-height: 1.33;
color: #32324d;
}
.c40 {
padding-right: 8px;
}
.c37 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
cursor: pointer;
padding: 8px;
border-radius: 4px;
background: #ffffff;
border: 1px solid #dcdce4;
}
.c37 svg {
height: 12px;
width: 12px;
}
.c37 svg > g,
.c37 svg path {
fill: #ffffff;
}
.c37[aria-disabled='true'] {
pointer-events: none;
}
.c38 {
padding: 8px 16px;
background: #4945ff;
border: none;
border: 1px solid #4945ff;
background: #4945ff;
}
.c38 .c39 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c38 .c41 {
color: #ffffff;
}
.c38[aria-disabled='true'] {
border: 1px solid #dcdce4;
background: #eaeaef;
}
.c38[aria-disabled='true'] .c41 {
color: #666687;
}
.c38[aria-disabled='true'] svg > g,
.c38[aria-disabled='true'] svg path {
fill: #666687;
}
.c38[aria-disabled='true']:active {
border: 1px solid #dcdce4;
background: #eaeaef;
}
.c38[aria-disabled='true']:active .c41 {
color: #666687;
}
.c38[aria-disabled='true']:active svg > g,
.c38[aria-disabled='true']:active svg path {
fill: #666687;
}
.c38:hover {
border: 1px solid #7b79ff;
background: #7b79ff;
}
.c38:active {
border: 1px solid #4945ff;
background: #4945ff;
}
.c1 {
background: #f6f6f9;
padding-top: 56px;
padding-right: 56px;
padding-bottom: 56px;
padding-left: 56px;
}
.c7 {
padding-right: 56px;
padding-left: 56px;
}
.c2 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c3 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c4 {
font-weight: 600;
font-size: 2rem;
line-height: 1.25;
color: #32324d;
}
.c5 {
font-weight: 400;
font-size: 0.875rem;
line-height: 1.43;
color: #666687;
}
.c6 {
font-size: 1rem;
line-height: 1.5;
}
.c8 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
.c8 > * {
margin-top: 0;
margin-bottom: 0;
}
.c8 > * + * {
margin-top: 32px;
}
.c10 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
.c10 > * {
margin-top: 0;
margin-bottom: 0;
}
.c10 > * + * {
margin-top: 16px;
}
.c11 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
.c11 > * {
margin-top: 0;
margin-bottom: 0;
}
.c11 > * + * {
margin-top: 4px;
}
.c12 {
font-weight: 500;
font-size: 1rem;
line-height: 1.25;
color: #32324d;
}
.c13 {
font-weight: 400;
font-size: 0.875rem;
line-height: 1.43;
color: #32324d;
}
.c19 {
font-weight: 500;
font-size: 0.75rem;
line-height: 1.33;
color: #32324d;
}
.c18 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c20 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c22 {
border: none;
padding-left: 16px;
padding-right: 16px;
color: #32324d;
font-weight: 400;
font-size: 0.875rem;
display: block;
width: 100%;
height: 2.5rem;
}
.c22::-webkit-input-placeholder {
color: #8e8ea9;
opacity: 1;
}
.c22::-moz-placeholder {
color: #8e8ea9;
opacity: 1;
}
.c22:-ms-input-placeholder {
color: #8e8ea9;
opacity: 1;
}
.c22::placeholder {
color: #8e8ea9;
opacity: 1;
}
.c22:disabled {
background: inherit;
color: inherit;
}
.c22:focus {
outline: none;
}
.c21 {
border: 1px solid #dcdce4;
border-radius: 4px;
background: #ffffff;
overflow: hidden;
color: #666687;
background: #eaeaef;
}
.c21:focus-within {
border: 1px solid #4945ff;
}
.c35 {
border: 1px solid #dcdce4;
border-radius: 4px;
background: #ffffff;
overflow: hidden;
}
.c35:focus-within {
border: 1px solid #4945ff;
}
.c17 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
.c17 > * {
margin-top: 0;
margin-bottom: 0;
}
.c17 > * + * {
margin-top: 4px;
}
.c16 textarea {
height: 5rem;
}
.c0 {
outline: none;
}
.c9 {
background: #ffffff;
padding-top: 24px;
padding-right: 32px;
padding-bottom: 24px;
padding-left: 32px;
border-radius: 4px;
box-shadow: 0px 1px 4px rgba(33,33,52,0.1);
}
.c14 {
display: grid;
grid-template-columns: repeat(12,1fr);
gap: 20px;
}
.c15 {
grid-column: span 6;
word-break: break-all;
}
.c36 {
grid-column: span 7;
word-break: break-all;
}
.c26 {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
width: 100%;
background: transparent;
border: none;
}
.c26:focus {
outline: none;
}
.c24 {
font-weight: 500;
font-size: 0.75rem;
line-height: 1.33;
color: #32324d;
}
.c31 {
font-weight: 400;
font-size: 0.875rem;
line-height: 1.43;
color: #666687;
}
.c30 {
padding-right: 16px;
padding-left: 16px;
}
.c32 {
padding-left: 12px;
}
.c27 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c29 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c23 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
.c23 > * {
margin-top: 0;
margin-bottom: 0;
}
.c23 > * + * {
margin-top: 4px;
}
.c25 {
position: relative;
border: 1px solid #dcdce4;
padding-right: 12px;
border-radius: 4px;
background: #ffffff;
overflow: hidden;
color: #666687;
background: #eaeaef;
}
.c25:focus-within {
border: 1px solid #4945ff;
}
.c33 {
background: transparent;
border: none;
position: relative;
z-index: 1;
}
.c33 svg {
height: 0.6875rem;
width: 0.6875rem;
}
.c33 svg path {
fill: #666687;
}
.c34 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
background: none;
border: none;
}
.c34 svg {
width: 0.375rem;
}
.c28 {
min-height: 2.5rem;
}
@media (max-width:68.75rem) {
.c15 {
grid-column: span 12;
}
}
@media (max-width:34.375rem) {
.c15 {
grid-column: span;
}
}
@media (max-width:68.75rem) {
.c36 {
grid-column: span 12;
}
}
@media (max-width:34.375rem) {
.c36 {
grid-column: span;
}
}
<main
aria-busy="false"
aria-labelledby="title"
class="c0"
id="main-content"
tabindex="-1"
>
<div
class=""
style="height: 0px;"
>
<div
class="c1"
data-strapi-header="true"
>
<div
class="c2"
>
<div
class="c3"
>
<h1
class="c4"
id="title"
>
Email settings
</h1>
</div>
</div>
<p
class="c5 c6"
>
Test the settings for the email plugin
</p>
</div>
</div>
<div
class="c7"
>
<form>
<div
class="c8"
>
<div
class="c9"
>
<div
class="c10"
>
<div
class="c11"
>
<h2
class="c12"
>
Configuration
</h2>
<span
class="c13"
>
Configuration
</span>
</div>
<div
class="c14"
>
<div
class="c15"
>
<div
class=""
>
<div
class="c16"
>
<div>
<div
class="c17"
>
<div
class="c18"
>
<label
class="c19"
for="textinput-4"
>
Default shipper email
</label>
</div>
<div
class="c20 c21"
disabled=""
>
<input
aria-invalid="false"
class="c22"
disabled=""
id="textinput-4"
name="shipper-email"
placeholder="ex: Strapi No-Reply <no-reply@strapi.io>"
value=""
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="c15"
>
<div
class=""
>
<div
class="c16"
>
<div>
<div
class="c17"
>
<div
class="c18"
>
<label
class="c19"
for="textinput-5"
>
Default response email
</label>
</div>
<div
class="c20 c21"
disabled=""
>
<input
aria-invalid="false"
class="c22"
disabled=""
id="textinput-5"
name="response-email"
placeholder="ex: Strapi <example@strapi.io>"
value=""
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="c15"
>
<div
class=""
>
<div>
<div
class="c23"
>
<span
class="c24"
for="select-2"
id="select-2-label"
>
Email provider
</span>
<div
class="c25"
disabled=""
>
<button
aria-disabled="true"
aria-expanded="false"
aria-haspopup="listbox"
aria-labelledby="select-2-label select-2-content"
class="c26"
id="select-2"
name="email-provider"
type="button"
/>
<div
class="c27 c28"
>
<div
class="c29"
>
<div
class="c30"
>
<span
class="c31"
id="select-2-content"
>
Select...
</span>
</div>
</div>
<div
class="c29"
>
<button
aria-hidden="true"
class="c32 c33 c34"
tabindex="-1"
>
<svg
fill="none"
height="1em"
viewBox="0 0 14 8"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
d="M14 .889a.86.86 0 01-.26.625L7.615 7.736A.834.834 0 017 8a.834.834 0 01-.615-.264L.26 1.514A.861.861 0 010 .889c0-.24.087-.45.26-.625A.834.834 0 01.875 0h12.25c.237 0 .442.088.615.264a.86.86 0 01.26.625z"
fill="#32324D"
fill-rule="evenodd"
/>
</svg>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="c9"
>
<div
class="c10"
>
<h2
class="c12"
>
Send a test mail
</h2>
<div
class="c14"
>
<div
class="c15"
>
<div
class=""
>
<div
class="c16"
>
<div>
<div
class="c17"
>
<div
class="c18"
>
<label
class="c19"
for="textinput-6"
>
Test delivery email address
</label>
</div>
<div
class="c20 c35"
>
<input
aria-invalid="false"
class="c22"
id="textinput-6"
name="test-address"
placeholder="ex: developer@example.com"
value=""
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="c36"
>
<div
class=""
>
<button
aria-disabled="false"
class="c37 c38"
type="submit"
>
<div
aria-hidden="true"
class="c39 c40"
>
<svg
fill="none"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M20.727 2.97a.2.2 0 01.286 0l2.85 2.89a.2.2 0 010 .28L9.554 20.854a.2.2 0 01-.285 0l-9.13-9.243a.2.2 0 010-.281l2.85-2.892a.2.2 0 01.284 0l6.14 6.209L20.726 2.97z"
fill="#212134"
/>
</svg>
</div>
<span
class="c41 c42"
>
Test email
</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</main>
`);
});
});

View File

@ -0,0 +1,21 @@
import { setupServer } from 'msw/node';
import { rest } from 'msw';
const handlers = [
rest.get('*/email/settings', (req, res, ctx) => {
return res(
ctx.delay(100),
ctx.status(200),
ctx.json({
config: {
provider: '',
settings: { defaultFrom: '', defaultReplyTo: '', testAddress: '' },
},
})
);
}),
];
const server = setupServer(...handlers);
export default server;

View File

@ -0,0 +1,13 @@
import { axiosInstance } from '../../../../../../admin/admin/src/core/utils';
const fetchEmailSettings = async () => {
const { data } = await axiosInstance.get('/email/settings');
return data.config;
};
const postEmailTest = async body => {
await axiosInstance.post('/email/test', body);
};
export { fetchEmailSettings, postEmailTest };

View File

@ -1,22 +1,18 @@
{ {
"Settings.button.test-email": "Test email", "Settings.email.plugin.button.test-email": "Test email",
"Settings.form.label.defaultFrom": "Default shipper email", "Settings.email.plugin.label.defaultFrom": "Default shipper email",
"Settings.form.label.defaultReplyTo": "Default response email", "Settings.email.plugin.label.defaultReplyTo": "Default response email",
"Settings.form.label.provider": "Email provider", "Settings.email.plugin.label.provider": "Email provider",
"Settings.form.label.testAddress": "Test delivery email address", "Settings.email.plugin.label.testAddress": "Test delivery email address",
"Settings.form.placeholder.defaultFrom": "ex: Strapi No-Reply <no-reply@strapi.io>", "Settings.email.plugin.placeholder.defaultFrom": "ex: Strapi No-Reply <no-reply@strapi.io>",
"Settings.form.placeholder.defaultReplyTo": "ex: Strapi <example@strapi.io>", "Settings.email.plugin.placeholder.defaultReplyTo": "ex: Strapi <example@strapi.io>",
"Settings.form.placeholder.testAddress": "ex: developer@example.com", "Settings.email.plugin.placeholder.testAddress": "ex: developer@example.com",
"Settings.form.text.configuration": "The plugin is configured through the {file} file, checkout this {link} for the documentation.", "Settings.email.plugin.text.configuration": "The plugin is configured through the {file} file, checkout this {link} for the documentation.",
"Settings.form.title.config": "Configuration", "Settings.email.plugin.title.config": "Configuration",
"Settings.form.title.test": "Send a test email", "Settings.email.plugin.title.test": "Send a test email",
"Settings.notification.config.error": "Failed to retrieve the email config", "Settings.email.plugin.notification.config.error": "Failed to retrieve the email config",
"Settings.notification.test.error": "Failed to send a test mail to {to}", "Settings.email.plugin.notification.test.error": "Failed to send a test mail to {to}",
"Settings.notification.test.success": "Email test succeeded, check the {to} mailbox", "Settings.email.plugin.notification.test.success": "Email test succeeded, check the {to} mailbox",
"Settings.subTitle": "Test the settings for the email plugin", "Settings.email.plugin.subTitle": "Test the settings for the email plugin",
"Settings.title": "Email settings", "Settings.email.plugin.title": "Email settings"
"SettingsNav.link.settings": "Email settings",
"SettingsNav.section-label": "Email plugin",
"plugin.description.long": "Send emails.",
"plugin.description.short": "Send emails."
} }