@eduwork/dsh-mail 0.1.2 → 0.2.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.en.md +6 -0
- package/CHANGELOG.md +6 -0
- package/README.md +4 -4
- package/README_EN.md +5 -5
- package/THIRD_PARTY_NOTICES.en.md +2 -0
- package/THIRD_PARTY_NOTICES.md +2 -0
- package/docs/EDUWORK-MIGRATION.en.md +2 -2
- package/docs/EDUWORK-MIGRATION.md +2 -2
- package/docs/architecture.en.md +3 -3
- package/docs/architecture.md +3 -3
- package/docs/compatibility.en.md +5 -6
- package/docs/compatibility.md +5 -6
- package/docs/getting-started.en.md +6 -6
- package/docs/getting-started.md +6 -6
- package/docs/security-model.en.md +4 -0
- package/docs/security-model.md +4 -0
- package/lib/client.js +167 -157
- package/lib/index.js +171 -36
- package/package.json +24 -16
package/lib/client.js
CHANGED
|
@@ -29,126 +29,133 @@ window.__ModuleLoader__.load({
|
|
|
29
29
|
let react = require("react");
|
|
30
30
|
react = __toESM(react, 1);
|
|
31
31
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
32
|
+
//#region src/client/locale.ts
|
|
33
|
+
const LOCALE_NS = "settings.mailAssistant";
|
|
34
|
+
const dictionaries = {
|
|
35
|
+
"zh": {
|
|
36
|
+
"nav": "邮件助手",
|
|
37
|
+
"title": "邮件助手",
|
|
38
|
+
"description": "让 Agent 通过标准 IMAP 只读检索邮件,并按当前权限模式通过 SMTP 发信。它不是邮箱客户端,不会移动、删除、归档或修改邮件状态。",
|
|
39
|
+
"loading": "正在读取配置…",
|
|
40
|
+
"save": "保存",
|
|
41
|
+
"saving": "正在保存…",
|
|
42
|
+
"saved": "配置已保存,新调用立即生效。",
|
|
43
|
+
"readPermission": "允许 Agent 读信",
|
|
44
|
+
"readHint": "可列出目录、分页查找、读取邮件和下载附件;IMAP 始终只读。",
|
|
45
|
+
"sendPermission": "允许 Agent 发信",
|
|
46
|
+
"sendHint": "可发送纯文本邮件;普通权限逐次确认,Full Access 不再弹窗。",
|
|
47
|
+
"identity": "邮箱账号",
|
|
48
|
+
"identityHint": "先填写日常使用的邮箱信息。多数邮箱要求使用客户端授权码,而不是网页登录密码。",
|
|
49
|
+
"email": "邮箱地址",
|
|
50
|
+
"emailHint": "用于收信和发信。",
|
|
51
|
+
"username": "登录用户名",
|
|
52
|
+
"usernameHint": "仅当服务商要求时填写;留空则使用邮箱地址。",
|
|
53
|
+
"fromName": "发件人显示名称",
|
|
54
|
+
"fromNameHint": "收件人看到的名称;可留空。",
|
|
55
|
+
"inbox": "收件箱目录",
|
|
56
|
+
"inboxHint": "通常保持 INBOX。",
|
|
57
|
+
"password": "密码 / 客户端授权码",
|
|
58
|
+
"passwordHint": "安全写入本机凭据存储,不会写进 settings.yaml,也不会回显。",
|
|
59
|
+
"configured": "已保存",
|
|
60
|
+
"missing": "未填写",
|
|
61
|
+
"credentialPlaceholder": "输入授权码;已保存时留空不会改变",
|
|
62
|
+
"clearPassword": "清除授权码",
|
|
63
|
+
"servers": "邮箱服务器",
|
|
64
|
+
"serversHint": "选择常见服务商可自动填写;单位邮箱或自建邮箱请选择“手动配置”。",
|
|
65
|
+
"preset": "邮箱服务商",
|
|
66
|
+
"custom": "手动配置",
|
|
67
|
+
"imap": "收信(IMAP)",
|
|
68
|
+
"smtp": "发信(SMTP)",
|
|
69
|
+
"host": "服务器地址",
|
|
70
|
+
"port": "端口",
|
|
71
|
+
"tls": "加密",
|
|
72
|
+
"implicit": "隐式 TLS",
|
|
73
|
+
"starttls": "STARTTLS",
|
|
74
|
+
"advanced": "高级设置",
|
|
75
|
+
"advancedHint": "登录用户名、收件箱目录和安全上限通常不需要修改。",
|
|
76
|
+
"collapse": "收起",
|
|
77
|
+
"agentAccess": "开放给 Agent",
|
|
78
|
+
"agentAccessHint": "账号和服务器保存好后,再按需要分别开放读信或发信。",
|
|
79
|
+
"permissionNeedsSetup": "请先填写邮箱地址、授权码和相应的服务器。",
|
|
80
|
+
"limits": "安全上限",
|
|
81
|
+
"bodyLimit": "正文字符",
|
|
82
|
+
"messageLimit": "整封邮件字节",
|
|
83
|
+
"attachmentLimit": "附件总字节",
|
|
84
|
+
"usage": "保存后,在对话里让 Agent“查一下最近邮件”即可验证。插件不会在启动或保存时主动连接邮箱。",
|
|
85
|
+
"error": "保存失败",
|
|
86
|
+
"reload": "重新加载",
|
|
87
|
+
"unavailable": "当前连接未提供此设置命名空间。",
|
|
88
|
+
"readOnly": "当前连接为只读模式,无法保存设置。",
|
|
89
|
+
"credentialPartial": "授权码已经保存,但其他配置保存失败;请修正后再次保存。"
|
|
90
|
+
},
|
|
91
|
+
"en": {
|
|
92
|
+
"nav": "Mail assistant",
|
|
93
|
+
"title": "Mail assistant",
|
|
94
|
+
"description": "Let the agent search mail through read-only IMAP and send through SMTP under the current permission preset. This is not a mail client: it never moves, deletes, archives, or changes message state.",
|
|
95
|
+
"loading": "Loading configuration…",
|
|
96
|
+
"save": "Save",
|
|
97
|
+
"saving": "Saving…",
|
|
98
|
+
"saved": "Saved. New calls use the configuration immediately.",
|
|
99
|
+
"readPermission": "Allow the agent to read mail",
|
|
100
|
+
"readHint": "List folders, page through searches, read messages, and download attachments. IMAP always stays read-only.",
|
|
101
|
+
"sendPermission": "Allow the agent to send mail",
|
|
102
|
+
"sendHint": "Send plain-text messages. Ordinary permissions ask each time; Full Access does not prompt.",
|
|
103
|
+
"identity": "Mailbox account",
|
|
104
|
+
"identityHint": "Start with the mailbox information you normally use. Most providers require an app password instead of the web-login password.",
|
|
105
|
+
"email": "Email address",
|
|
106
|
+
"emailHint": "Used for both incoming and outgoing mail.",
|
|
107
|
+
"username": "Login username",
|
|
108
|
+
"usernameHint": "Only set this when required by your provider; otherwise the email address is used.",
|
|
109
|
+
"fromName": "Sender display name",
|
|
110
|
+
"fromNameHint": "The name recipients see; optional.",
|
|
111
|
+
"inbox": "Inbox folder",
|
|
112
|
+
"inboxHint": "Usually keep INBOX.",
|
|
113
|
+
"password": "Password / app password",
|
|
114
|
+
"passwordHint": "Stored securely in the local credential store. It is never written to settings.yaml or returned to this page.",
|
|
115
|
+
"configured": "Saved",
|
|
116
|
+
"missing": "Missing",
|
|
117
|
+
"credentialPlaceholder": "Enter an app password; leave blank to keep the saved value",
|
|
118
|
+
"clearPassword": "Clear app password",
|
|
119
|
+
"servers": "Mail servers",
|
|
120
|
+
"serversHint": "Choose a common provider to fill these automatically, or use Manual configuration for institutional and self-hosted mail.",
|
|
121
|
+
"preset": "Mail provider",
|
|
122
|
+
"custom": "Manual configuration",
|
|
123
|
+
"imap": "Incoming (IMAP)",
|
|
124
|
+
"smtp": "Outgoing (SMTP)",
|
|
125
|
+
"host": "Server address",
|
|
126
|
+
"port": "Port",
|
|
127
|
+
"tls": "Encryption",
|
|
128
|
+
"implicit": "Implicit TLS",
|
|
129
|
+
"starttls": "STARTTLS",
|
|
130
|
+
"advanced": "Advanced settings",
|
|
131
|
+
"advancedHint": "Login username, inbox folder, and safety limits usually need no changes.",
|
|
132
|
+
"collapse": "Collapse",
|
|
133
|
+
"agentAccess": "Agent access",
|
|
134
|
+
"agentAccessHint": "After saving the account and servers, enable reading and sending independently as needed.",
|
|
135
|
+
"permissionNeedsSetup": "Enter the email address, app password, and corresponding server first.",
|
|
136
|
+
"limits": "Safety limits",
|
|
137
|
+
"bodyLimit": "Body characters",
|
|
138
|
+
"messageLimit": "Whole-message bytes",
|
|
139
|
+
"attachmentLimit": "Total attachment bytes",
|
|
140
|
+
"usage": "After saving, ask the agent to find recent mail. The plugin never connects to a mailbox during startup or save.",
|
|
141
|
+
"error": "Save failed",
|
|
142
|
+
"reload": "Reload",
|
|
143
|
+
"unavailable": "This connection does not expose the mail settings namespace.",
|
|
144
|
+
"readOnly": "This connection exposes settings in read-only mode.",
|
|
145
|
+
"credentialPartial": "The app password was stored, but the remaining settings failed to save. Fix the form and save again."
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
//#endregion
|
|
32
149
|
//#region src/client/index.tsx
|
|
33
150
|
const inject = [
|
|
34
151
|
"slots",
|
|
152
|
+
"locale",
|
|
35
153
|
"remote",
|
|
36
154
|
"remote.credentials",
|
|
37
|
-
"
|
|
155
|
+
"configForms"
|
|
38
156
|
];
|
|
39
157
|
const NS = "dsh-mail-assistant";
|
|
40
158
|
const PASSWORD_REF = "DSH_MAIL_ASSISTANT_PASSWORD";
|
|
41
|
-
const copy = typeof navigator !== "undefined" && navigator.language.toLowerCase().startsWith("zh") ? {
|
|
42
|
-
nav: "邮件助手",
|
|
43
|
-
title: "邮件助手",
|
|
44
|
-
description: "让 Agent 通过标准 IMAP 只读检索邮件,并按当前 DSH 权限模式通过 SMTP 发信。它不是邮箱客户端,不会移动、删除、归档或修改邮件状态。",
|
|
45
|
-
loading: "正在读取配置…",
|
|
46
|
-
save: "保存",
|
|
47
|
-
saving: "正在保存…",
|
|
48
|
-
saved: "配置已保存,新调用立即生效。",
|
|
49
|
-
readPermission: "允许 Agent 读信",
|
|
50
|
-
readHint: "可列出目录、分页查找、读取邮件和下载附件;IMAP 始终只读。",
|
|
51
|
-
sendPermission: "允许 Agent 发信",
|
|
52
|
-
sendHint: "可发送纯文本邮件;普通权限逐次确认,Full Access 不再弹窗。",
|
|
53
|
-
identity: "邮箱账号",
|
|
54
|
-
identityHint: "先填写日常使用的邮箱信息。多数邮箱要求使用客户端授权码,而不是网页登录密码。",
|
|
55
|
-
email: "邮箱地址",
|
|
56
|
-
emailHint: "用于收信和发信。",
|
|
57
|
-
username: "登录用户名",
|
|
58
|
-
usernameHint: "仅当服务商要求时填写;留空则使用邮箱地址。",
|
|
59
|
-
fromName: "发件人显示名称",
|
|
60
|
-
fromNameHint: "收件人看到的名称;可留空。",
|
|
61
|
-
inbox: "收件箱目录",
|
|
62
|
-
inboxHint: "通常保持 INBOX。",
|
|
63
|
-
password: "密码 / 客户端授权码",
|
|
64
|
-
passwordHint: "安全写入 DSH 凭据存储,不会写进 settings.yaml,也不会回显。",
|
|
65
|
-
configured: "已保存",
|
|
66
|
-
missing: "未填写",
|
|
67
|
-
credentialPlaceholder: "输入授权码;已保存时留空不会改变",
|
|
68
|
-
clearPassword: "清除授权码",
|
|
69
|
-
servers: "邮箱服务器",
|
|
70
|
-
serversHint: "选择常见服务商可自动填写;单位邮箱或自建邮箱请选择“手动配置”。",
|
|
71
|
-
preset: "邮箱服务商",
|
|
72
|
-
custom: "手动配置",
|
|
73
|
-
imap: "收信(IMAP)",
|
|
74
|
-
smtp: "发信(SMTP)",
|
|
75
|
-
host: "服务器地址",
|
|
76
|
-
port: "端口",
|
|
77
|
-
tls: "加密",
|
|
78
|
-
implicit: "隐式 TLS",
|
|
79
|
-
starttls: "STARTTLS",
|
|
80
|
-
advanced: "高级设置",
|
|
81
|
-
advancedHint: "登录用户名、收件箱目录和安全上限通常不需要修改。",
|
|
82
|
-
collapse: "收起",
|
|
83
|
-
agentAccess: "开放给 Agent",
|
|
84
|
-
agentAccessHint: "账号和服务器保存好后,再按需要分别开放读信或发信。",
|
|
85
|
-
permissionNeedsSetup: "请先填写邮箱地址、授权码和相应的服务器。",
|
|
86
|
-
limits: "安全上限",
|
|
87
|
-
bodyLimit: "正文字符",
|
|
88
|
-
messageLimit: "整封邮件字节",
|
|
89
|
-
attachmentLimit: "附件总字节",
|
|
90
|
-
usage: "保存后,在对话里让 Agent“查一下最近邮件”即可验证。插件不会在启动或保存时主动连接邮箱。",
|
|
91
|
-
error: "保存失败",
|
|
92
|
-
reload: "重新加载",
|
|
93
|
-
unavailable: "当前 DSH 连接未提供此设置命名空间。",
|
|
94
|
-
readOnly: "当前连接为只读模式,无法保存设置。",
|
|
95
|
-
credentialPartial: "授权码已经保存,但其他配置保存失败;请修正后再次保存。"
|
|
96
|
-
} : {
|
|
97
|
-
nav: "Mail assistant",
|
|
98
|
-
title: "Mail assistant",
|
|
99
|
-
description: "Let the agent search mail through read-only IMAP and send through SMTP under the current DSH permission preset. This is not a mail client: it never moves, deletes, archives, or changes message state.",
|
|
100
|
-
loading: "Loading configuration…",
|
|
101
|
-
save: "Save",
|
|
102
|
-
saving: "Saving…",
|
|
103
|
-
saved: "Saved. New calls use the configuration immediately.",
|
|
104
|
-
readPermission: "Allow the agent to read mail",
|
|
105
|
-
readHint: "List folders, page through searches, read messages, and download attachments. IMAP always stays read-only.",
|
|
106
|
-
sendPermission: "Allow the agent to send mail",
|
|
107
|
-
sendHint: "Send plain-text messages. Ordinary permissions ask each time; Full Access does not prompt.",
|
|
108
|
-
identity: "Mailbox account",
|
|
109
|
-
identityHint: "Start with the mailbox information you normally use. Most providers require an app password instead of the web-login password.",
|
|
110
|
-
email: "Email address",
|
|
111
|
-
emailHint: "Used for both incoming and outgoing mail.",
|
|
112
|
-
username: "Login username",
|
|
113
|
-
usernameHint: "Only set this when required by your provider; otherwise the email address is used.",
|
|
114
|
-
fromName: "Sender display name",
|
|
115
|
-
fromNameHint: "The name recipients see; optional.",
|
|
116
|
-
inbox: "Inbox folder",
|
|
117
|
-
inboxHint: "Usually keep INBOX.",
|
|
118
|
-
password: "Password / app password",
|
|
119
|
-
passwordHint: "Stored securely in DSH Credentials. It is never written to settings.yaml or returned to this page.",
|
|
120
|
-
configured: "Saved",
|
|
121
|
-
missing: "Missing",
|
|
122
|
-
credentialPlaceholder: "Enter an app password; leave blank to keep the saved value",
|
|
123
|
-
clearPassword: "Clear app password",
|
|
124
|
-
servers: "Mail servers",
|
|
125
|
-
serversHint: "Choose a common provider to fill these automatically, or use Manual configuration for institutional and self-hosted mail.",
|
|
126
|
-
preset: "Mail provider",
|
|
127
|
-
custom: "Manual configuration",
|
|
128
|
-
imap: "Incoming (IMAP)",
|
|
129
|
-
smtp: "Outgoing (SMTP)",
|
|
130
|
-
host: "Server address",
|
|
131
|
-
port: "Port",
|
|
132
|
-
tls: "Encryption",
|
|
133
|
-
implicit: "Implicit TLS",
|
|
134
|
-
starttls: "STARTTLS",
|
|
135
|
-
advanced: "Advanced settings",
|
|
136
|
-
advancedHint: "Login username, inbox folder, and safety limits usually need no changes.",
|
|
137
|
-
collapse: "Collapse",
|
|
138
|
-
agentAccess: "Agent access",
|
|
139
|
-
agentAccessHint: "After saving the account and servers, enable reading and sending independently as needed.",
|
|
140
|
-
permissionNeedsSetup: "Enter the email address, app password, and corresponding server first.",
|
|
141
|
-
limits: "Safety limits",
|
|
142
|
-
bodyLimit: "Body characters",
|
|
143
|
-
messageLimit: "Whole-message bytes",
|
|
144
|
-
attachmentLimit: "Total attachment bytes",
|
|
145
|
-
usage: "After saving, ask the agent to find recent mail. The plugin never connects to a mailbox during startup or save.",
|
|
146
|
-
error: "Save failed",
|
|
147
|
-
reload: "Reload",
|
|
148
|
-
unavailable: "This DSH connection does not expose the mail settings namespace.",
|
|
149
|
-
readOnly: "This connection exposes settings in read-only mode.",
|
|
150
|
-
credentialPartial: "The app password was stored, but the remaining settings failed to save. Fix the form and save again."
|
|
151
|
-
};
|
|
152
159
|
const defaults = {
|
|
153
160
|
readEnabled: false,
|
|
154
161
|
sendEnabled: false,
|
|
@@ -221,7 +228,7 @@ window.__ModuleLoader__.load({
|
|
|
221
228
|
for (const [key, candidate] of Object.entries(presets)) if (Object.entries(candidate).every(([field, expected]) => value[field] === expected)) return key;
|
|
222
229
|
return "custom";
|
|
223
230
|
}
|
|
224
|
-
function MailSettings({ service }) {
|
|
231
|
+
function MailSettings({ t, service }) {
|
|
225
232
|
const [draft, setDraft] = (0, react.useState)(null);
|
|
226
233
|
const [passwordConfigured, setPasswordConfigured] = (0, react.useState)(false);
|
|
227
234
|
const [credentialWritable, setCredentialWritable] = (0, react.useState)(false);
|
|
@@ -282,10 +289,10 @@ window.__ModuleLoader__.load({
|
|
|
282
289
|
path: [field],
|
|
283
290
|
value
|
|
284
291
|
}));
|
|
285
|
-
await service.scope.mutate(ops, snapshot.revision);
|
|
286
|
-
setNotice(
|
|
292
|
+
if (await service.scope.mutate(ops, snapshot.revision) === false) throw new Error(t("error"));
|
|
293
|
+
setNotice(t("saved"));
|
|
287
294
|
} catch (cause) {
|
|
288
|
-
setError(passwordStored ?
|
|
295
|
+
setError(passwordStored ? t("credentialPartial") : cause?.message || `${t("error")}`);
|
|
289
296
|
} finally {
|
|
290
297
|
setBusy(false);
|
|
291
298
|
}
|
|
@@ -298,7 +305,7 @@ window.__ModuleLoader__.load({
|
|
|
298
305
|
await unwrap(service.credentials.unset(PASSWORD_REF));
|
|
299
306
|
setPasswordConfigured(false);
|
|
300
307
|
setPassword("");
|
|
301
|
-
setNotice(
|
|
308
|
+
setNotice(t("saved"));
|
|
302
309
|
} catch (cause) {
|
|
303
310
|
setError(cause?.message || String(cause));
|
|
304
311
|
} finally {
|
|
@@ -369,10 +376,10 @@ window.__ModuleLoader__.load({
|
|
|
369
376
|
};
|
|
370
377
|
if (!draft) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
371
378
|
style: styles.root,
|
|
372
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: error || (snapshot.status === "unavailable" ?
|
|
379
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: error || (snapshot.status === "unavailable" ? t("unavailable") : t("loading")) }), error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
373
380
|
style: styles.button,
|
|
374
381
|
onClick: () => load(),
|
|
375
|
-
children:
|
|
382
|
+
children: t("reload")
|
|
376
383
|
})]
|
|
377
384
|
});
|
|
378
385
|
const credentialReady = passwordConfigured || password !== "";
|
|
@@ -420,7 +427,7 @@ window.__ModuleLoader__.load({
|
|
|
420
427
|
color: "#a82332",
|
|
421
428
|
fontSize: 11
|
|
422
429
|
},
|
|
423
|
-
children:
|
|
430
|
+
children: t("permissionNeedsSetup")
|
|
424
431
|
})
|
|
425
432
|
] })]
|
|
426
433
|
});
|
|
@@ -453,20 +460,20 @@ window.__ModuleLoader__.load({
|
|
|
453
460
|
marginTop: 10
|
|
454
461
|
},
|
|
455
462
|
children: [
|
|
456
|
-
field(
|
|
457
|
-
field(
|
|
463
|
+
field(t("host"), `${prefix}Host`),
|
|
464
|
+
field(t("port"), `${prefix}Port`, "number"),
|
|
458
465
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
459
466
|
style: styles.label,
|
|
460
|
-
children: [
|
|
467
|
+
children: [t("tls"), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
461
468
|
value: draft[`${prefix}Tls`],
|
|
462
469
|
onChange: (event) => set(`${prefix}Tls`, event.currentTarget.value),
|
|
463
470
|
style: styles.input,
|
|
464
471
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
465
472
|
value: "implicit",
|
|
466
|
-
children:
|
|
473
|
+
children: t("implicit")
|
|
467
474
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
468
475
|
value: "starttls",
|
|
469
|
-
children:
|
|
476
|
+
children: t("starttls")
|
|
470
477
|
})]
|
|
471
478
|
})]
|
|
472
479
|
})
|
|
@@ -481,7 +488,7 @@ window.__ModuleLoader__.load({
|
|
|
481
488
|
margin: 0,
|
|
482
489
|
fontSize: 21
|
|
483
490
|
},
|
|
484
|
-
children:
|
|
491
|
+
children: t("title")
|
|
485
492
|
}),
|
|
486
493
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
487
494
|
style: {
|
|
@@ -490,7 +497,7 @@ window.__ModuleLoader__.load({
|
|
|
490
497
|
fontSize: 12,
|
|
491
498
|
lineHeight: 1.65
|
|
492
499
|
},
|
|
493
|
-
children:
|
|
500
|
+
children: t("description")
|
|
494
501
|
}),
|
|
495
502
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
496
503
|
style: styles.card,
|
|
@@ -500,7 +507,7 @@ window.__ModuleLoader__.load({
|
|
|
500
507
|
margin: 0,
|
|
501
508
|
fontSize: 15
|
|
502
509
|
},
|
|
503
|
-
children:
|
|
510
|
+
children: t("identity")
|
|
504
511
|
}),
|
|
505
512
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
506
513
|
style: {
|
|
@@ -509,12 +516,12 @@ window.__ModuleLoader__.load({
|
|
|
509
516
|
fontSize: 11,
|
|
510
517
|
lineHeight: 1.55
|
|
511
518
|
},
|
|
512
|
-
children:
|
|
519
|
+
children: t("identityHint")
|
|
513
520
|
}),
|
|
514
521
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
515
522
|
style: styles.grid,
|
|
516
523
|
children: [
|
|
517
|
-
field(
|
|
524
|
+
field(t("email"), "email", "email", t("emailHint")),
|
|
518
525
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
519
526
|
style: styles.label,
|
|
520
527
|
children: [
|
|
@@ -524,7 +531,7 @@ window.__ModuleLoader__.load({
|
|
|
524
531
|
alignItems: "center",
|
|
525
532
|
gap: 7
|
|
526
533
|
},
|
|
527
|
-
children: [
|
|
534
|
+
children: [t("password"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
528
535
|
style: {
|
|
529
536
|
borderRadius: 999,
|
|
530
537
|
padding: "2px 7px",
|
|
@@ -532,7 +539,7 @@ window.__ModuleLoader__.load({
|
|
|
532
539
|
color: passwordConfigured ? "#32724e" : "#9d2f3f",
|
|
533
540
|
background: passwordConfigured ? "#eaf6ef" : "#f8e9ec"
|
|
534
541
|
},
|
|
535
|
-
children: passwordConfigured ?
|
|
542
|
+
children: passwordConfigured ? t("configured") : t("missing")
|
|
536
543
|
})]
|
|
537
544
|
}),
|
|
538
545
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
@@ -540,11 +547,11 @@ window.__ModuleLoader__.load({
|
|
|
540
547
|
autoComplete: "new-password",
|
|
541
548
|
value: password,
|
|
542
549
|
disabled: busy || !credentialWritable,
|
|
543
|
-
placeholder:
|
|
550
|
+
placeholder: t("credentialPlaceholder"),
|
|
544
551
|
onChange: (event) => setPassword(event.currentTarget.value),
|
|
545
552
|
style: styles.input
|
|
546
553
|
}),
|
|
547
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children:
|
|
554
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("passwordHint") }),
|
|
548
555
|
passwordConfigured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
549
556
|
type: "button",
|
|
550
557
|
disabled: busy || !credentialWritable,
|
|
@@ -554,11 +561,11 @@ window.__ModuleLoader__.load({
|
|
|
554
561
|
color: "#a82332"
|
|
555
562
|
},
|
|
556
563
|
onClick: clearPassword,
|
|
557
|
-
children:
|
|
564
|
+
children: t("clearPassword")
|
|
558
565
|
})
|
|
559
566
|
]
|
|
560
567
|
}),
|
|
561
|
-
field(
|
|
568
|
+
field(t("fromName"), "fromName", "text", t("fromNameHint"))
|
|
562
569
|
]
|
|
563
570
|
})
|
|
564
571
|
]
|
|
@@ -578,7 +585,7 @@ window.__ModuleLoader__.load({
|
|
|
578
585
|
margin: 0,
|
|
579
586
|
fontSize: 15
|
|
580
587
|
},
|
|
581
|
-
children:
|
|
588
|
+
children: t("servers")
|
|
582
589
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
583
590
|
style: {
|
|
584
591
|
margin: "6px 0 0",
|
|
@@ -586,20 +593,20 @@ window.__ModuleLoader__.load({
|
|
|
586
593
|
fontSize: 11,
|
|
587
594
|
lineHeight: 1.55
|
|
588
595
|
},
|
|
589
|
-
children:
|
|
596
|
+
children: t("serversHint")
|
|
590
597
|
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
591
598
|
style: {
|
|
592
599
|
...styles.label,
|
|
593
600
|
minWidth: 210
|
|
594
601
|
},
|
|
595
|
-
children: [
|
|
602
|
+
children: [t("preset"), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
596
603
|
value: preset,
|
|
597
604
|
onChange: (event) => applyPreset(event.currentTarget.value),
|
|
598
605
|
style: styles.input,
|
|
599
606
|
children: [
|
|
600
607
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
601
608
|
value: "custom",
|
|
602
|
-
children:
|
|
609
|
+
children: t("custom")
|
|
603
610
|
}),
|
|
604
611
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
605
612
|
value: "gmail",
|
|
@@ -629,7 +636,7 @@ window.__ModuleLoader__.load({
|
|
|
629
636
|
display: "grid",
|
|
630
637
|
gap: 11
|
|
631
638
|
},
|
|
632
|
-
children: [server("imap",
|
|
639
|
+
children: [server("imap", t("imap")), server("smtp", t("smtp"))]
|
|
633
640
|
})]
|
|
634
641
|
}),
|
|
635
642
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
@@ -651,7 +658,7 @@ window.__ModuleLoader__.load({
|
|
|
651
658
|
display: "block",
|
|
652
659
|
fontSize: 13
|
|
653
660
|
},
|
|
654
|
-
children:
|
|
661
|
+
children: t("advanced")
|
|
655
662
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
656
663
|
style: {
|
|
657
664
|
display: "block",
|
|
@@ -659,28 +666,28 @@ window.__ModuleLoader__.load({
|
|
|
659
666
|
color: colors.secondary,
|
|
660
667
|
fontSize: 11
|
|
661
668
|
},
|
|
662
|
-
children:
|
|
663
|
-
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: advancedOpen ?
|
|
669
|
+
children: t("advancedHint")
|
|
670
|
+
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: advancedOpen ? t("collapse") : "›" })]
|
|
664
671
|
}), advancedOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
665
672
|
style: { marginTop: 14 },
|
|
666
673
|
children: [
|
|
667
674
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
668
675
|
style: styles.grid,
|
|
669
|
-
children: [field(
|
|
676
|
+
children: [field(t("username"), "username", "text", t("usernameHint")), field(t("inbox"), "inboxFolder", "text", t("inboxHint"))]
|
|
670
677
|
}),
|
|
671
678
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
672
679
|
style: {
|
|
673
680
|
margin: "17px 0 10px",
|
|
674
681
|
fontSize: 13
|
|
675
682
|
},
|
|
676
|
-
children:
|
|
683
|
+
children: t("limits")
|
|
677
684
|
}),
|
|
678
685
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
679
686
|
style: styles.grid,
|
|
680
687
|
children: [
|
|
681
|
-
field(
|
|
682
|
-
field(
|
|
683
|
-
field(
|
|
688
|
+
field(t("bodyLimit"), "maxBodyChars", "number"),
|
|
689
|
+
field(t("messageLimit"), "maxMessageBytes", "number"),
|
|
690
|
+
field(t("attachmentLimit"), "maxAttachmentBytes", "number")
|
|
684
691
|
]
|
|
685
692
|
})
|
|
686
693
|
]
|
|
@@ -694,7 +701,7 @@ window.__ModuleLoader__.load({
|
|
|
694
701
|
margin: 0,
|
|
695
702
|
fontSize: 15
|
|
696
703
|
},
|
|
697
|
-
children:
|
|
704
|
+
children: t("agentAccess")
|
|
698
705
|
}),
|
|
699
706
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
700
707
|
style: {
|
|
@@ -703,11 +710,11 @@ window.__ModuleLoader__.load({
|
|
|
703
710
|
fontSize: 11,
|
|
704
711
|
lineHeight: 1.55
|
|
705
712
|
},
|
|
706
|
-
children:
|
|
713
|
+
children: t("agentAccessHint")
|
|
707
714
|
}),
|
|
708
715
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
709
716
|
style: styles.grid,
|
|
710
|
-
children: [permission("readEnabled",
|
|
717
|
+
children: [permission("readEnabled", t("readPermission"), t("readHint"), readReady), permission("sendEnabled", t("sendPermission"), t("sendHint"), sendReady)]
|
|
711
718
|
})
|
|
712
719
|
]
|
|
713
720
|
}),
|
|
@@ -717,7 +724,7 @@ window.__ModuleLoader__.load({
|
|
|
717
724
|
fontSize: 11,
|
|
718
725
|
lineHeight: 1.55
|
|
719
726
|
},
|
|
720
|
-
children:
|
|
727
|
+
children: t("usage")
|
|
721
728
|
}),
|
|
722
729
|
!snapshot.writable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
723
730
|
role: "status",
|
|
@@ -725,7 +732,7 @@ window.__ModuleLoader__.load({
|
|
|
725
732
|
color: colors.secondary,
|
|
726
733
|
fontSize: 12
|
|
727
734
|
},
|
|
728
|
-
children:
|
|
735
|
+
children: t("readOnly")
|
|
729
736
|
}),
|
|
730
737
|
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
731
738
|
role: "alert",
|
|
@@ -748,21 +755,24 @@ window.__ModuleLoader__.load({
|
|
|
748
755
|
disabled: busy || !snapshot.writable,
|
|
749
756
|
onClick: save,
|
|
750
757
|
style: styles.primary,
|
|
751
|
-
children: busy ?
|
|
758
|
+
children: busy ? t("saving") : t("save")
|
|
752
759
|
})
|
|
753
760
|
]
|
|
754
761
|
});
|
|
755
762
|
}
|
|
756
763
|
function apply(ctx) {
|
|
764
|
+
ctx.effect(() => ctx.locale.register(LOCALE_NS, dictionaries), "mail: dictionaries");
|
|
765
|
+
const t = ctx.locale.bind(LOCALE_NS);
|
|
757
766
|
const service = {
|
|
758
|
-
scope: ctx.
|
|
767
|
+
scope: ctx.configForms.get(NS),
|
|
759
768
|
credentials: ctx.remote.credentials
|
|
760
769
|
};
|
|
761
770
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
762
771
|
name: "settings.section",
|
|
763
772
|
id: "mail-assistant",
|
|
773
|
+
locale: LOCALE_NS,
|
|
764
774
|
order: 25,
|
|
765
|
-
label: () =>
|
|
775
|
+
label: () => t("nav"),
|
|
766
776
|
inject: () => ({ service })
|
|
767
777
|
}, MailSettings));
|
|
768
778
|
}
|