@actuate-media/cms-admin 0.42.4 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/__tests__/views/appearance-settings.render.test.js +47 -0
- package/dist/__tests__/views/appearance-settings.render.test.js.map +1 -1
- package/dist/__tests__/views/email-settings.render.test.d.ts +2 -0
- package/dist/__tests__/views/email-settings.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/email-settings.render.test.js +184 -0
- package/dist/__tests__/views/email-settings.render.test.js.map +1 -0
- package/dist/actuate-admin.css +1 -1
- package/dist/views/Settings.d.ts.map +1 -1
- package/dist/views/Settings.js +5 -3
- package/dist/views/Settings.js.map +1 -1
- package/dist/views/settings/BrandingCard.d.ts +1 -1
- package/dist/views/settings/BrandingCard.d.ts.map +1 -1
- package/dist/views/settings/BrandingCard.js +6 -2
- package/dist/views/settings/BrandingCard.js.map +1 -1
- package/dist/views/settings/EmailSettingsTab.d.ts +4 -0
- package/dist/views/settings/EmailSettingsTab.d.ts.map +1 -0
- package/dist/views/settings/EmailSettingsTab.js +75 -0
- package/dist/views/settings/EmailSettingsTab.js.map +1 -0
- package/dist/views/settings/useAppearanceSettings.d.ts +10 -0
- package/dist/views/settings/useAppearanceSettings.d.ts.map +1 -1
- package/dist/views/settings/useAppearanceSettings.js +54 -21
- package/dist/views/settings/useAppearanceSettings.js.map +1 -1
- package/dist/views/settings/useEmailSettings.d.ts +58 -0
- package/dist/views/settings/useEmailSettings.d.ts.map +1 -0
- package/dist/views/settings/useEmailSettings.js +209 -0
- package/dist/views/settings/useEmailSettings.js.map +1 -0
- package/package.json +2 -2
- package/src/__tests__/views/appearance-settings.render.test.tsx +67 -0
- package/src/__tests__/views/email-settings.render.test.tsx +225 -0
- package/src/views/Settings.tsx +13 -0
- package/src/views/settings/BrandingCard.tsx +13 -7
- package/src/views/settings/EmailSettingsTab.tsx +436 -0
- package/src/views/settings/useAppearanceSettings.ts +57 -21
- package/src/views/settings/useEmailSettings.ts +296 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @actuate-media/cms-admin
|
|
2
2
|
|
|
3
|
+
## 0.44.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- d6b21e7: Add Settings > Email: configure the transactional email provider from the admin UI.
|
|
8
|
+
- **cms-admin**: new Email tab in Settings with a provider picker (Resend, SMTP.com, Amazon SES, generic SMTP), per-provider credential fields, masked stored secrets (last-4 only, write-only inputs), a "Send test email" button, and notices for environment/platform-managed configuration.
|
|
9
|
+
- **cms-core**: new `__email_config__` store with API keys and SMTP passwords encrypted at rest (`CMS_ENCRYPTION_KEY`), `GET/PUT /email/settings` + `POST /email/settings/test` admin routes (test sends only to the signed-in admin's own address, rate-limited), and a DB-aware `resolveEmailSenderAsync()` used by invites, password resets, and form notifications. Resolution order: platform adapter → admin-configured settings → environment variables.
|
|
10
|
+
- **plugin-email**: registers a provider factory with cms-core so admin-configured settings build real Resend/SMTP.com/SES/SMTP senders without env vars.
|
|
11
|
+
|
|
12
|
+
## 0.43.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- 6027f23: Branding uploads now accept WebP, JPEG, GIF, and AVIF in addition to SVG and PNG. Favicons accept SVG, PNG, and WebP (lossy photographic formats stay excluded for crisp small-size rendering). The file-picker accept strings are derived from the validation allow-lists so they can't drift, validation errors show readable format names (e.g. "SVG, PNG, WebP"), and logo shape detection can no longer block an upload if image decoding fails.
|
|
17
|
+
|
|
3
18
|
## 0.42.4
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
|
@@ -40,6 +40,7 @@ const cmsApi = vi.fn(async (endpoint, options) => {
|
|
|
40
40
|
});
|
|
41
41
|
vi.mock('../../lib/api.js', () => ({ cmsApi: (e, o) => cmsApi(e, o) }));
|
|
42
42
|
const { AppearanceTab } = await import('../../views/settings/AppearanceTab.js');
|
|
43
|
+
const { LOGO_MIME, FAVICON_MIME } = await import('../../views/settings/useAppearanceSettings.js');
|
|
43
44
|
function baseData(overrides = {}) {
|
|
44
45
|
return {
|
|
45
46
|
appearance: {
|
|
@@ -119,6 +120,52 @@ describe('AppearanceTab', () => {
|
|
|
119
120
|
body: expect.stringContaining('"publicPrimaryLogoAssetId":"existing-logo"'),
|
|
120
121
|
})));
|
|
121
122
|
});
|
|
123
|
+
it('accepts modern image formats for logos (and a crisp subset for favicons)', () => {
|
|
124
|
+
// WebP is a first-class brand format — general media uploads are converted
|
|
125
|
+
// to WebP anyway, so re-selecting them from the library must work.
|
|
126
|
+
expect(LOGO_MIME).toEqual(expect.arrayContaining([
|
|
127
|
+
'image/svg+xml',
|
|
128
|
+
'image/png',
|
|
129
|
+
'image/webp',
|
|
130
|
+
'image/jpeg',
|
|
131
|
+
'image/gif',
|
|
132
|
+
'image/avif',
|
|
133
|
+
]));
|
|
134
|
+
expect(FAVICON_MIME).toEqual(expect.arrayContaining(['image/svg+xml', 'image/png', 'image/webp']));
|
|
135
|
+
// Favicons need crisp small-size rendering — lossy photographic formats stay out.
|
|
136
|
+
expect(FAVICON_MIME).not.toContain('image/jpeg');
|
|
137
|
+
});
|
|
138
|
+
it('uploads a WebP logo through the Media Center', async () => {
|
|
139
|
+
// happy-dom's Image never decodes blobs — fire onload so shape detection
|
|
140
|
+
// (raster path, used for all non-SVG formats) completes.
|
|
141
|
+
vi.stubGlobal('Image', class {
|
|
142
|
+
naturalWidth = 400;
|
|
143
|
+
naturalHeight = 100;
|
|
144
|
+
onload = null;
|
|
145
|
+
onerror = null;
|
|
146
|
+
set src(_v) {
|
|
147
|
+
queueMicrotask(() => this.onload?.());
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
render(_jsx(AppearanceTab, { role: "ADMIN" }));
|
|
151
|
+
await screen.findByText('Branding');
|
|
152
|
+
const input = screen.getByLabelText('Primary logo');
|
|
153
|
+
const file = new File([new Uint8Array([0x52, 0x49, 0x46, 0x46])], 'logo.webp', {
|
|
154
|
+
type: 'image/webp',
|
|
155
|
+
});
|
|
156
|
+
fireEvent.change(input, { target: { files: [file] } });
|
|
157
|
+
await waitFor(() => expect(cmsApi).toHaveBeenCalledWith('/media/upload', expect.objectContaining({ method: 'POST' })));
|
|
158
|
+
vi.unstubAllGlobals();
|
|
159
|
+
});
|
|
160
|
+
it('rejects an unsupported upload type client-side with a readable error', async () => {
|
|
161
|
+
render(_jsx(AppearanceTab, { role: "ADMIN" }));
|
|
162
|
+
await screen.findByText('Branding');
|
|
163
|
+
const input = screen.getByLabelText('Primary logo');
|
|
164
|
+
const file = new File(['%PDF-1.4'], 'brochure.pdf', { type: 'application/pdf' });
|
|
165
|
+
fireEvent.change(input, { target: { files: [file] } });
|
|
166
|
+
expect(await screen.findByText(/unsupported file type/i)).toBeTruthy();
|
|
167
|
+
expect(cmsApi.mock.calls.some(([endpoint]) => endpoint === '/media/upload')).toBe(false);
|
|
168
|
+
});
|
|
122
169
|
it('is read-only for non-admins', async () => {
|
|
123
170
|
render(_jsx(AppearanceTab, { role: "EDITOR" }));
|
|
124
171
|
expect(await screen.findByText(/read-only access to appearance/i)).toBeTruthy();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appearance-settings.render.test.js","sourceRoot":"","sources":["../../../src/__tests__/views/appearance-settings.render.test.tsx"],"names":[],"mappings":";AAAA,gCAAgC;AAChC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAE3E,8EAA8E;AAC9E,6EAA6E;AAC7E,IAAI,cAAmB,CAAA;AAEvB,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,QAAgB,EAAE,OAA6C,EAAE,EAAE;IAC7F,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,KAAK,CAAA;IACvC,IAAI,QAAQ,KAAK,aAAa,IAAI,MAAM,KAAK,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,EAAE,CAAA;IAChG,IAAI,QAAQ,KAAK,mBAAmB,IAAI,MAAM,KAAK,KAAK;QACtD,OAAO,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,eAAe,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAA;IAC9D,IAAI,QAAQ,KAAK,mBAAmB,IAAI,MAAM,KAAK,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAA;IAC1F,IAAI,QAAQ,KAAK,eAAe,IAAI,MAAM,KAAK,MAAM;QACnD,OAAO;YACL,IAAI,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,+BAA+B,EAAE,QAAQ,EAAE,eAAe,EAAE;YACzF,MAAM,EAAE,GAAG;SACZ,CAAA;IACH,IAAI,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,MAAM,KAAK,KAAK;QACpD,OAAO;YACL,IAAI,EAAE;gBACJ,KAAK,EAAE;oBACL;wBACE,EAAE,EAAE,eAAe;wBACnB,QAAQ,EAAE,cAAc;wBACxB,UAAU,EAAE,sCAAsC;wBAClD,GAAG,EAAE,sCAAsC;wBAC3C,QAAQ,EAAE,WAAW;wBACrB,QAAQ,EAAE,IAAI;wBACd,KAAK,EAAE,GAAG;wBACV,MAAM,EAAE,GAAG;qBACZ;iBACF;aACF;YACD,MAAM,EAAE,GAAG;SACZ,CAAA;IACH,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAA;AAClC,CAAC,CAAC,CAAA;AAEF,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAS,EAAE,CAAW,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAQ,CAAC,EAAE,CAAC,CAAC,CAAA;AAEhG,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,uCAAuC,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"appearance-settings.render.test.js","sourceRoot":"","sources":["../../../src/__tests__/views/appearance-settings.render.test.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-settings.render.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/views/email-settings.render.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// @vitest-environment happy-dom
|
|
3
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
5
|
+
const EMPTY_RESPONSE = {
|
|
6
|
+
settings: { provider: null, hasApiKey: false, hasSmtpPass: false },
|
|
7
|
+
envProvider: null,
|
|
8
|
+
factoryAvailable: true,
|
|
9
|
+
envSenderActive: false,
|
|
10
|
+
platformAdapter: false,
|
|
11
|
+
};
|
|
12
|
+
let getResponse = EMPTY_RESPONSE;
|
|
13
|
+
let putResponse = null;
|
|
14
|
+
let testResponse = {
|
|
15
|
+
data: { success: true, sentTo: 'admin@example.com' },
|
|
16
|
+
status: 200,
|
|
17
|
+
};
|
|
18
|
+
const cmsApi = vi.fn(async (endpoint, options) => {
|
|
19
|
+
const method = options?.method ?? 'GET';
|
|
20
|
+
if (endpoint === '/email/settings' && method === 'GET') {
|
|
21
|
+
return { data: getResponse, status: 200 };
|
|
22
|
+
}
|
|
23
|
+
if (endpoint === '/email/settings' && method === 'PUT') {
|
|
24
|
+
return putResponse
|
|
25
|
+
? { data: putResponse, status: 200 }
|
|
26
|
+
: { error: 'unexpected PUT', status: 500 };
|
|
27
|
+
}
|
|
28
|
+
if (endpoint === '/email/settings/test' && method === 'POST') {
|
|
29
|
+
return testResponse;
|
|
30
|
+
}
|
|
31
|
+
return { data: {}, status: 200 };
|
|
32
|
+
});
|
|
33
|
+
vi.mock('../../lib/api.js', () => ({
|
|
34
|
+
cmsApi: (e, o) => cmsApi(e, o),
|
|
35
|
+
ensureCsrfToken: vi.fn(async () => { }),
|
|
36
|
+
}));
|
|
37
|
+
const { EmailSettingsTab } = await import('../../views/settings/EmailSettingsTab.js');
|
|
38
|
+
function deepClone(v) {
|
|
39
|
+
return JSON.parse(JSON.stringify(v));
|
|
40
|
+
}
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
cmsApi.mockClear();
|
|
43
|
+
getResponse = deepClone(EMPTY_RESPONSE);
|
|
44
|
+
putResponse = null;
|
|
45
|
+
testResponse = { data: { success: true, sentTo: 'admin@example.com' }, status: 200 };
|
|
46
|
+
});
|
|
47
|
+
describe('EmailSettingsTab', () => {
|
|
48
|
+
it('renders the provider picker with the unconfigured state', async () => {
|
|
49
|
+
render(_jsx(EmailSettingsTab, { role: "ADMIN" }));
|
|
50
|
+
expect(await screen.findByRole('radio', { name: 'None' })).toBeTruthy();
|
|
51
|
+
expect(screen.getByRole('radio', { name: 'Resend' })).toBeTruthy();
|
|
52
|
+
expect(screen.getByRole('radio', { name: 'SMTP.com' })).toBeTruthy();
|
|
53
|
+
expect(screen.getByRole('radio', { name: 'Amazon SES' })).toBeTruthy();
|
|
54
|
+
expect(screen.getByRole('radio', { name: 'SMTP server' })).toBeTruthy();
|
|
55
|
+
expect(screen.getByText(/No email provider configured/)).toBeTruthy();
|
|
56
|
+
});
|
|
57
|
+
it('saves an SMTP.com configuration with the entered key (PUT payload contract)', async () => {
|
|
58
|
+
putResponse = {
|
|
59
|
+
settings: {
|
|
60
|
+
provider: 'smtpcom',
|
|
61
|
+
from: 'noreply@example.com',
|
|
62
|
+
channel: 'transactional',
|
|
63
|
+
hasApiKey: true,
|
|
64
|
+
apiKeyLast4: '-key',
|
|
65
|
+
hasSmtpPass: false,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
render(_jsx(EmailSettingsTab, { role: "ADMIN" }));
|
|
69
|
+
fireEvent.click(await screen.findByRole('radio', { name: 'SMTP.com' }));
|
|
70
|
+
fireEvent.change(screen.getByLabelText('Sender address'), {
|
|
71
|
+
target: { value: 'noreply@example.com' },
|
|
72
|
+
});
|
|
73
|
+
fireEvent.change(screen.getByLabelText('API key'), {
|
|
74
|
+
target: { value: 'smtpcom-secret-key' },
|
|
75
|
+
});
|
|
76
|
+
fireEvent.change(screen.getByLabelText('Sender channel'), {
|
|
77
|
+
target: { value: 'transactional' },
|
|
78
|
+
});
|
|
79
|
+
fireEvent.click(screen.getByRole('button', { name: 'Save Changes' }));
|
|
80
|
+
await waitFor(() => {
|
|
81
|
+
const put = cmsApi.mock.calls.find(([e, o]) => e === '/email/settings' && o?.method === 'PUT');
|
|
82
|
+
expect(put).toBeTruthy();
|
|
83
|
+
expect(JSON.parse(put[1].body)).toEqual({
|
|
84
|
+
provider: 'smtpcom',
|
|
85
|
+
from: 'noreply@example.com',
|
|
86
|
+
apiKey: 'smtpcom-secret-key',
|
|
87
|
+
channel: 'transactional',
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
// After save the key input is cleared and the masked hint appears.
|
|
91
|
+
expect(screen.getByLabelText('API key').value).toBe('');
|
|
92
|
+
expect(await screen.findByText(/ends in -key/)).toBeTruthy();
|
|
93
|
+
});
|
|
94
|
+
it('omits the apiKey from the payload when a stored key is kept', async () => {
|
|
95
|
+
getResponse = {
|
|
96
|
+
...deepClone(EMPTY_RESPONSE),
|
|
97
|
+
settings: {
|
|
98
|
+
provider: 'resend',
|
|
99
|
+
from: 'old@example.com',
|
|
100
|
+
hasApiKey: true,
|
|
101
|
+
apiKeyLast4: 'k3y9',
|
|
102
|
+
hasSmtpPass: false,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
putResponse = {
|
|
106
|
+
settings: {
|
|
107
|
+
provider: 'resend',
|
|
108
|
+
from: 'new@example.com',
|
|
109
|
+
hasApiKey: true,
|
|
110
|
+
apiKeyLast4: 'k3y9',
|
|
111
|
+
hasSmtpPass: false,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
render(_jsx(EmailSettingsTab, { role: "ADMIN" }));
|
|
115
|
+
const from = await screen.findByLabelText('Sender address');
|
|
116
|
+
expect(await screen.findByText(/ends in k3y9/)).toBeTruthy();
|
|
117
|
+
fireEvent.change(from, { target: { value: 'new@example.com' } });
|
|
118
|
+
fireEvent.click(screen.getByRole('button', { name: 'Save Changes' }));
|
|
119
|
+
await waitFor(() => {
|
|
120
|
+
const put = cmsApi.mock.calls.find(([e, o]) => e === '/email/settings' && o?.method === 'PUT');
|
|
121
|
+
expect(put).toBeTruthy();
|
|
122
|
+
const body = JSON.parse(put[1].body);
|
|
123
|
+
expect(body).toEqual({ provider: 'resend', from: 'new@example.com' });
|
|
124
|
+
expect(body).not.toHaveProperty('apiKey');
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
it('sends a test email and shows the result', async () => {
|
|
128
|
+
getResponse = {
|
|
129
|
+
...deepClone(EMPTY_RESPONSE),
|
|
130
|
+
settings: {
|
|
131
|
+
provider: 'resend',
|
|
132
|
+
from: 'a@b.co',
|
|
133
|
+
hasApiKey: true,
|
|
134
|
+
apiKeyLast4: 'k3y9',
|
|
135
|
+
hasSmtpPass: false,
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
render(_jsx(EmailSettingsTab, { role: "ADMIN" }));
|
|
139
|
+
fireEvent.click(await screen.findByRole('button', { name: /Send test email/ }));
|
|
140
|
+
await waitFor(() => expect(cmsApi).toHaveBeenCalledWith('/email/settings/test', expect.objectContaining({ method: 'POST' })));
|
|
141
|
+
expect(await screen.findByText(/Test email sent to admin@example.com/)).toBeTruthy();
|
|
142
|
+
});
|
|
143
|
+
it('surfaces a failed test send', async () => {
|
|
144
|
+
getResponse = {
|
|
145
|
+
...deepClone(EMPTY_RESPONSE),
|
|
146
|
+
settings: {
|
|
147
|
+
provider: 'resend',
|
|
148
|
+
from: 'a@b.co',
|
|
149
|
+
hasApiKey: true,
|
|
150
|
+
hasSmtpPass: false,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
testResponse = { error: 'SMTP.com API error (401): bad key', status: 502 };
|
|
154
|
+
render(_jsx(EmailSettingsTab, { role: "ADMIN" }));
|
|
155
|
+
fireEvent.click(await screen.findByRole('button', { name: /Send test email/ }));
|
|
156
|
+
expect(await screen.findByText(/SMTP\.com API error \(401\)/)).toBeTruthy();
|
|
157
|
+
});
|
|
158
|
+
it('shows the env-managed notice and disables editing for non-admins', async () => {
|
|
159
|
+
getResponse = {
|
|
160
|
+
...deepClone(EMPTY_RESPONSE),
|
|
161
|
+
envProvider: 'resend',
|
|
162
|
+
envSenderActive: true,
|
|
163
|
+
};
|
|
164
|
+
render(_jsx(EmailSettingsTab, { role: "EDITOR" }));
|
|
165
|
+
expect(await screen.findByText(/read-only access/)).toBeTruthy();
|
|
166
|
+
expect(screen.getByText(/Environment variables currently configure/)).toBeTruthy();
|
|
167
|
+
expect(screen.getByRole('radio', { name: 'Resend' }).disabled).toBe(true);
|
|
168
|
+
});
|
|
169
|
+
it('warns when the email plugin is missing for a configured provider', async () => {
|
|
170
|
+
getResponse = {
|
|
171
|
+
...deepClone(EMPTY_RESPONSE),
|
|
172
|
+
factoryAvailable: false,
|
|
173
|
+
settings: {
|
|
174
|
+
provider: 'resend',
|
|
175
|
+
from: 'a@b.co',
|
|
176
|
+
hasApiKey: true,
|
|
177
|
+
hasSmtpPass: false,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
render(_jsx(EmailSettingsTab, { role: "ADMIN" }));
|
|
181
|
+
expect(await screen.findByText(/requires the email plugin/)).toBeTruthy();
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
//# sourceMappingURL=email-settings.render.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-settings.render.test.js","sourceRoot":"","sources":["../../../src/__tests__/views/email-settings.render.test.tsx"],"names":[],"mappings":"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"}
|