merge newui branch
This commit is contained in:
385
ui/src/settings/mail/pageMailSettings.js
Normal file
385
ui/src/settings/mail/pageMailSettings.js
Normal file
@@ -0,0 +1,385 @@
|
||||
import { settingsSidebar } from "../settingsSidebar";
|
||||
|
||||
export function pageMailSettings(route) {
|
||||
app.store.title = "Mail settings";
|
||||
|
||||
const tlsOptions = [
|
||||
{ label: "Auto (StartTLS)", value: false },
|
||||
{ label: "Always", value: true },
|
||||
];
|
||||
|
||||
const authMethods = [
|
||||
{ label: "PLAIN (default)", value: "PLAIN" },
|
||||
{ label: "LOGIN", value: "LOGIN" },
|
||||
];
|
||||
|
||||
const data = store({
|
||||
isLoading: false,
|
||||
isSaving: false,
|
||||
formSettings: null,
|
||||
initSerialized: "null",
|
||||
showMoreOptions: false,
|
||||
get hasChanges() {
|
||||
return data.initSerialized != JSON.stringify(data.formSettings);
|
||||
},
|
||||
});
|
||||
|
||||
loadSettings();
|
||||
|
||||
async function loadSettings() {
|
||||
data.isLoading = true;
|
||||
|
||||
try {
|
||||
const settings = await app.pb.settings.getAll();
|
||||
init(settings);
|
||||
|
||||
data.isLoading = false;
|
||||
} catch (err) {
|
||||
if (!err.isAbort) {
|
||||
app.checkApiError(err);
|
||||
// data.isLoading = false; don't reset in case of a server error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (data.isSaving || !data.hasChanges) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.isSaving = true;
|
||||
|
||||
try {
|
||||
const redacted = app.utils.filterRedactedProps(data.formSettings);
|
||||
const settings = await app.pb.settings.update(redacted);
|
||||
init(settings);
|
||||
|
||||
app.toasts.success("Successfully saved mail settings.");
|
||||
} catch (err) {
|
||||
app.checkApiError(err);
|
||||
}
|
||||
|
||||
data.isSaving = false;
|
||||
}
|
||||
|
||||
function init(settings = {}) {
|
||||
// refresh local app settings
|
||||
app.store.settings = JSON.parse(JSON.stringify(settings));
|
||||
|
||||
data.formSettings = {
|
||||
meta: settings?.meta || {},
|
||||
smtp: settings?.smtp || {},
|
||||
};
|
||||
|
||||
if (!data.formSettings.smtp.authMethod) {
|
||||
data.formSettings.smtp.authMethod = authMethods[0].value;
|
||||
}
|
||||
|
||||
data.initSerialized = JSON.stringify(data.formSettings);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
data.formSettings = JSON.parse(data.initSerialized);
|
||||
}
|
||||
|
||||
return t.div(
|
||||
{ pbEvent: "pageMailSettings", className: "page page-mail-settings" },
|
||||
settingsSidebar(),
|
||||
t.div(
|
||||
{ className: "page-content full-height" },
|
||||
t.header(
|
||||
{ className: "page-header" },
|
||||
t.nav(
|
||||
{ className: "breadcrumbs" },
|
||||
t.div({ className: "breadcrumb-item" }, "Settings"),
|
||||
t.div({ className: "breadcrumb-item" }, () => app.store.title),
|
||||
),
|
||||
),
|
||||
t.div(
|
||||
{ className: "wrapper m-b-base" },
|
||||
() => {
|
||||
if (data.isLoading) {
|
||||
return t.div({ className: "block txt-center" }, t.span({ className: "loader lg" }));
|
||||
}
|
||||
|
||||
return t.form(
|
||||
{
|
||||
pbEvent: "mailSettingsForm",
|
||||
className: "grid mail-settings-form",
|
||||
inert: () => data.isSaving,
|
||||
onsubmit: (e) => {
|
||||
e.preventDefault();
|
||||
save();
|
||||
},
|
||||
},
|
||||
t.div(
|
||||
{ className: "col-lg-12 txt-lg" },
|
||||
t.p(null, "Configure common settings for sending emails."),
|
||||
),
|
||||
t.div(
|
||||
{ className: "col-lg-6" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label({ htmlFor: "meta.senderName" }, "Sender name"),
|
||||
t.input({
|
||||
id: "meta.senderName",
|
||||
name: "meta.senderName",
|
||||
type: "text",
|
||||
required: true,
|
||||
value: () => data.formSettings.meta.senderName || "",
|
||||
oninput: (e) => (data.formSettings.meta.senderName = e.target.value),
|
||||
}),
|
||||
),
|
||||
),
|
||||
t.div(
|
||||
{ className: "col-lg-6" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label({ htmlFor: "meta.senderAddress" }, "Sender address"),
|
||||
t.input({
|
||||
id: "meta.senderAddress",
|
||||
name: "meta.senderAddress",
|
||||
type: "email",
|
||||
required: true,
|
||||
value: () => data.formSettings.meta.senderAddress || "",
|
||||
oninput: (e) => (data.formSettings.meta.senderAddress = e.target.value),
|
||||
}),
|
||||
),
|
||||
),
|
||||
t.div(
|
||||
{ className: "col-lg-12" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.input({
|
||||
id: "smtp.enabled",
|
||||
name: "smtp.enabled",
|
||||
type: "checkbox",
|
||||
className: "switch",
|
||||
checked: () => !!data.formSettings.smtp.enabled,
|
||||
onchange: (e) => (data.formSettings.smtp.enabled = e.target.checked),
|
||||
}),
|
||||
t.label(
|
||||
{ htmlFor: "smtp.enabled" },
|
||||
t.span(
|
||||
{ className: "txt" },
|
||||
"Use SMTP mail server ",
|
||||
t.strong(null, "(recommended)"),
|
||||
),
|
||||
t.i({
|
||||
className: "ri-information-line link-faded",
|
||||
ariaDescription: app.attrs.tooltip(
|
||||
`By default PocketBase uses the unix "sendmail" command for sending emails. For better emails deliverability it is recommended to use a SMTP mail server.`,
|
||||
),
|
||||
}),
|
||||
),
|
||||
),
|
||||
// SMTP
|
||||
app.components.slide(
|
||||
() => data.formSettings.smtp.enabled,
|
||||
t.div(
|
||||
{ className: "grid m-t-sm" },
|
||||
t.div(
|
||||
{ className: "col-lg-4" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label({ htmlFor: "smtp.host" }, "SMTP server host"),
|
||||
t.input({
|
||||
id: "smtp.host",
|
||||
name: "smtp.host",
|
||||
type: "text",
|
||||
required: () => data.formSettings.smtp.enabled,
|
||||
value: () => data.formSettings.smtp.host || "",
|
||||
oninput: (e) => data.formSettings.smtp.host = e.target.value,
|
||||
}),
|
||||
),
|
||||
),
|
||||
t.div(
|
||||
{ className: "col-lg-2" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label({ htmlFor: "smtp.port" }, "Port"),
|
||||
t.input({
|
||||
id: "smtp.port",
|
||||
name: "smtp.port",
|
||||
type: "number",
|
||||
min: 0,
|
||||
step: 1,
|
||||
required: () => data.formSettings.smtp.enabled,
|
||||
value: () => data.formSettings.smtp.port || "",
|
||||
oninput: (e) =>
|
||||
data.formSettings.smtp.port = parseInt(e.target.value, 10),
|
||||
}),
|
||||
),
|
||||
),
|
||||
t.div(
|
||||
{ className: "col-lg-3" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label({ htmlFor: "smtp.username" }, "Username"),
|
||||
t.input({
|
||||
id: "smtp.username",
|
||||
name: "smtp.username",
|
||||
type: "text",
|
||||
autocomplete: "off",
|
||||
value: () => data.formSettings.smtp.username || "",
|
||||
oninput: (e) => data.formSettings.smtp.username = e.target.value,
|
||||
}),
|
||||
),
|
||||
),
|
||||
t.div(
|
||||
{ className: "col-lg-3" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label({ htmlFor: "smtp.password" }, "Password"),
|
||||
t.input({
|
||||
id: "smtp.password",
|
||||
name: "smtp.password",
|
||||
type: "password",
|
||||
autocomplete: "new-password",
|
||||
value: () => data.formSettings.smtp.password || "",
|
||||
oninput: (e) => data.formSettings.smtp.password = e.target.value,
|
||||
onkeyup: (e) => {
|
||||
if (
|
||||
e.key == "Backspace"
|
||||
&& typeof data.formSettings.smtp.password === "undefined"
|
||||
) {
|
||||
data.formSettings.smtp.password = "";
|
||||
}
|
||||
},
|
||||
placeholder: () =>
|
||||
typeof data.formSettings.smtp.password !== "undefined"
|
||||
? ""
|
||||
: "* * * * * *",
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
// additional options
|
||||
t.button(
|
||||
{
|
||||
type: "button",
|
||||
className: "btn secondary sm m-t-sm",
|
||||
onclick: () => data.showMoreOptions = !data.showMoreOptions,
|
||||
},
|
||||
t.span(
|
||||
{ className: "txt" },
|
||||
() => data.showMoreOptions ? "Hide more options" : "Show more options",
|
||||
),
|
||||
t.i({
|
||||
className: () =>
|
||||
data.showMoreOptions ? "ri-arrow-drop-up-line" : "ri-arrow-drop-down-line",
|
||||
}),
|
||||
),
|
||||
app.components.slide(
|
||||
() => data.showMoreOptions,
|
||||
t.div(
|
||||
{ className: "grid m-t-sm" },
|
||||
t.div(
|
||||
{ className: "col-lg-3" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label({ htmlFor: "smtp.tls" }, "TLS encryption"),
|
||||
app.components.select({
|
||||
id: "smtp.tls",
|
||||
name: "smtp.tls",
|
||||
required: true,
|
||||
options: tlsOptions,
|
||||
value: () => data.formSettings.smtp.tls || false,
|
||||
onchange: (selected) => {
|
||||
data.formSettings.smtp.tls = selected?.[0]?.value;
|
||||
},
|
||||
}),
|
||||
),
|
||||
),
|
||||
t.div(
|
||||
{ className: "col-lg-3" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label({ htmlFor: "smtp.authMethod" }, "AUTH method"),
|
||||
app.components.select({
|
||||
id: "smtp.authMethod",
|
||||
name: "smtp.authMethod",
|
||||
required: true,
|
||||
options: authMethods,
|
||||
value: () =>
|
||||
data.formSettings.smtp.authMethod || authMethods[0].value,
|
||||
onchange: (selected) => {
|
||||
data.formSettings.smtp.authMethod = selected?.[0]?.value;
|
||||
},
|
||||
}),
|
||||
),
|
||||
),
|
||||
t.div(
|
||||
{ className: "col-lg-6" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.label(
|
||||
{ htmlFor: "smtp.localName" },
|
||||
t.span({ className: "txt" }, "EHLO/HELO domain"),
|
||||
t.i({
|
||||
className: "ri-information-line link-hint tooltip-top",
|
||||
ariaDescription: app.attrs.tooltip(
|
||||
"Some SMTP servers, such as the Gmail SMTP-relay, requires a proper domain name in the inital EHLO/HELO exchange and will reject attempts to use localhost.",
|
||||
),
|
||||
}),
|
||||
),
|
||||
t.input({
|
||||
id: "smtp.localName",
|
||||
name: "smtp.localName",
|
||||
type: "text",
|
||||
placeholder: "Default to localhost",
|
||||
value: () => data.formSettings.smtp.localName || "",
|
||||
oninput: (e) => data.formSettings.smtp.localName = e.target.value,
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
t.div({ className: "col-lg-12" }, t.hr()),
|
||||
t.div(
|
||||
{ className: "col-lg-12" },
|
||||
t.div(
|
||||
{ className: "flex" },
|
||||
t.div({ className: "m-r-auto" }),
|
||||
() => {
|
||||
if (data.hasChanges) {
|
||||
return [
|
||||
t.button(
|
||||
{
|
||||
type: "button",
|
||||
className: "btn transparent secondary",
|
||||
onclick: reset,
|
||||
},
|
||||
t.span({ className: "txt" }, "Cancel"),
|
||||
),
|
||||
t.button(
|
||||
{
|
||||
className: () => `btn expanded ${data.isSaving ? "loading" : ""}`,
|
||||
disabled: () => !data.hasChanges || data.isSaving,
|
||||
},
|
||||
t.span({ className: "txt" }, "Save changes"),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
return t.button(
|
||||
{
|
||||
type: "button",
|
||||
className: () => `btn expanded outline`,
|
||||
onclick: () => app.modals.openMailTest(),
|
||||
},
|
||||
t.i({ className: "ri-mail-check-line" }),
|
||||
t.span({ className: "txt" }, "Send test email"),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
t.footer({ className: "page-footer" }, app.components.credits()),
|
||||
),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user