diff --git a/VERSION b/VERSION index 3c43790..c04c650 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.6 +1.2.7 diff --git a/apps/web/src/lib/language.tsx b/apps/web/src/lib/language.tsx index 43fa781..3031c83 100644 --- a/apps/web/src/lib/language.tsx +++ b/apps/web/src/lib/language.tsx @@ -183,6 +183,10 @@ const exactTranslations: Record = { "前往个人中心": { "zh-TW": "前往個人中心", en: "Go to profile" }, "请前往邮箱管理,创建、申请或联系管理员分配邮箱。": { "zh-TW": "請前往信箱管理,建立、申請或聯絡管理員分配信箱。", en: "Open mailbox management to create, request, or ask an administrator to assign a mailbox." }, "前往邮箱管理": { "zh-TW": "前往信箱管理", en: "Go to mailbox management" }, + "提示:尚未选择开放域名。请在“后台管理 → 系统设置 → 邮件”中至少勾选一个已启用域名。": { "zh-TW": "提示:尚未選擇開放網域。請在「後台管理 → 系統設定 → 郵件」中至少勾選一個已啟用網域。", en: "No domain is open for mailbox requests. Open Admin → System settings → Mail and select at least one active domain." }, + "提示:账号自助申请邮箱未开启。请在“后台管理 → 系统设置 → 邮件”中开启,并勾选开放域名。": { "zh-TW": "提示:帳號自助申請信箱尚未開啟。請在「後台管理 → 系統設定 → 郵件」中開啟,並勾選開放網域。", en: "Mailbox self-service is disabled. Enable it under Admin → System settings → Mail, then select the available domains." }, + "提示:当前账号暂不可创建新邮箱,请联系管理员开启账号自助申请邮箱。": { "zh-TW": "提示:目前帳號暫時無法建立新信箱,請聯絡管理員開啟帳號自助申請信箱。", en: "This account cannot create a mailbox. Ask an administrator to enable mailbox self-service." }, + "前往设置": { "zh-TW": "前往設定", en: "Open settings" }, "无邮箱前台权限": { "zh-TW": "無信箱前台權限", en: "No mailbox access" }, "当前账号未开启邮箱前台访问权限。": { "zh-TW": "目前帳號未開啟信箱前台存取權限。", en: "Mailbox access is not enabled for this account." }, "无邮件查看权限": { "zh-TW": "無郵件檢視權限", en: "No mail read permission" }, diff --git a/apps/web/src/pages/admin.tsx b/apps/web/src/pages/admin.tsx index ee8daf7..19ef8a6 100644 --- a/apps/web/src/pages/admin.tsx +++ b/apps/web/src/pages/admin.tsx @@ -27,6 +27,7 @@ import { hasAnyPermission, hasPermission } from "@/lib/permissions" import type { PermissionKey } from "@/lib/api-types" type Section = "overview" | "users" | "permissionGroups" | "domains" | "mailboxes" | "aliases" | "messages" | "sendAudit" | "settings" +type SettingsTab = "base" | "smtp" | "storage" | "mail" | "externalImap" | "templates" | "security" | "about" type PendingConfirm = { title: string; description?: string; confirmText: string; onConfirm: () => void } const sectionMeta: Record = { @@ -132,7 +133,7 @@ export function AdminPage() { {section === "aliases" && } {section === "messages" && } {section === "sendAudit" && } - {section === "settings" && } + {section === "settings" && } ) @@ -1018,7 +1019,7 @@ function AdminSendAuditSection({ mailboxes }: { mailboxes: MailboxType[] }) { ) } -function SystemSettingsSection({ settings, domains }: { settings?: SystemSettings; domains: Domain[] }) { +function SystemSettingsSection({ settings, domains, initialTab }: { settings?: SystemSettings; domains: Domain[]; initialTab?: string | null }) { const me = useMe() const user = me.data?.user const qc = useQueryClient() @@ -1030,7 +1031,8 @@ function SystemSettingsSection({ settings, domains }: { settings?: SystemSetting const canUpdateTemplates = hasPermission(user, "admin.templates.update") const canResetTemplates = hasPermission(user, "admin.templates.reset") const templates = useQuery({ queryKey: ["admin", "mail-templates"], queryFn: api.mailTemplates, enabled: canViewTemplates }) - const [settingsTab, setSettingsTab] = React.useState<"base" | "smtp" | "storage" | "mail" | "externalImap" | "templates" | "security" | "about">("base") + const requestedTab = initialTab as SettingsTab | undefined + const [settingsTab, setSettingsTab] = React.useState(() => requestedTab && ["base", "smtp", "storage", "mail", "externalImap", "templates", "security", "about"].includes(requestedTab) ? requestedTab : "base") const maildirHealth = useQuery({ queryKey: ["admin", "maildir-sync", "health"], queryFn: api.maildirSyncHealth, enabled: canSettingsView && settingsTab === "storage" }) const [smtpRequireTls, setSmtpRequireTls] = React.useState(false) const [allowInsecureHttp, setAllowInsecureHttp] = React.useState(true) diff --git a/apps/web/src/pages/profile.tsx b/apps/web/src/pages/profile.tsx index d97ced9..172a7f2 100644 --- a/apps/web/src/pages/profile.tsx +++ b/apps/web/src/pages/profile.tsx @@ -82,6 +82,7 @@ export function ProfilePage() { const canManageBlocked = hasPermission(user, "mail.blocked_senders.manage") const canViewStats = hasPermission(user, "mail.stats.view") const canApplyMailbox = hasPermission(user, "mail.mailboxes.apply") + const canConfigureMailboxApply = hasPermission(user, "admin.settings.update") const visibleTabKeys = tabKeys.filter((key) => { if (key === "profile") return true if (key === "mailboxes") return canAccessMail || canApplyMailbox @@ -453,6 +454,7 @@ export function ProfilePage() { mailboxes={canAccessMail ? mailboxes.data?.items || [] : []} applyOptions={mailboxApplyOptions.data} applyPending={applyMailbox.isPending} + canConfigureApply={canConfigureMailboxApply} selectedMailboxId={mailboxId} externalImapEnabled={externalImapEnabled} externalAccounts={externalImapAccounts.data?.items || []} @@ -464,6 +466,7 @@ export function ProfilePage() { onSelect={setMailboxId} onOpen={(id) => { if (!canAccessMail) return; setMailboxId(id); navigate("/") }} onApply={(payload) => applyMailbox.mutateAsync(payload).then(() => undefined)} + onConfigureApply={() => navigate("/admin?section=settings&settingsTab=mail")} onCreateExternal={(payload) => createExternalImap.mutate(payload)} onStartExternalOAuth={(provider, payload) => startExternalOAuth.mutate({ provider, ...payload })} onUpdateExternal={(id, payload) => updateExternalImap.mutate({ id, payload })} @@ -1000,6 +1003,7 @@ function MailboxManagement({ mailboxes, applyOptions, applyPending, + canConfigureApply, selectedMailboxId, externalImapEnabled, externalAccounts, @@ -1011,6 +1015,7 @@ function MailboxManagement({ onSelect, onOpen, onApply, + onConfigureApply, onCreateExternal, onStartExternalOAuth, onUpdateExternal, @@ -1022,6 +1027,7 @@ function MailboxManagement({ mailboxes: Mailbox[] applyOptions?: MailboxApplyOptions applyPending: boolean + canConfigureApply: boolean selectedMailboxId: string externalImapEnabled: boolean externalAccounts: ExternalImapAccount[] @@ -1033,6 +1039,7 @@ function MailboxManagement({ onSelect: (id: string) => void onOpen: (id: string) => void onApply: (payload: { domainId: string; localPart: string; displayName: string }) => Promise + onConfigureApply: () => void onCreateExternal: (payload: ExternalImapAccountPayload) => void onStartExternalOAuth: (provider: ExternalImapOAuthProvider, payload: { mailboxId: string; email: string; storageMode: ExternalImapStorageMode }) => void onUpdateExternal: (id: string, payload: ExternalImapAccountPayload) => void @@ -1208,9 +1215,16 @@ function MailboxManagement({ -

- {canApply ? "提示:邮箱数量受账号配额限制,管理员可在后台为单个账号调整可创建数量。" : "提示:当前账号暂不可创建新邮箱。"} -

+
+ {canApply + ? "提示:邮箱数量受账号配额限制,管理员可在后台为单个账号调整可创建数量。" + : canConfigureApply && applyOptions?.enabled + ? "提示:尚未选择开放域名。请在“后台管理 → 系统设置 → 邮件”中至少勾选一个已启用域名。" + : canConfigureApply + ? "提示:账号自助申请邮箱未开启。请在“后台管理 → 系统设置 → 邮件”中开启,并勾选开放域名。" + : "提示:当前账号暂不可创建新邮箱,请联系管理员开启账号自助申请邮箱。"} + {!canApply && canConfigureApply && } +