feat: warn on send when attachment keyword found but no file attached #172
This commit is contained in:
@@ -103,6 +103,8 @@ export function EmailComposer({
|
||||
const timeFormat = useSettingsStore((state) => state.timeFormat);
|
||||
const plainTextMode = useSettingsStore((state) => state.plainTextMode);
|
||||
const autoSelectReplyIdentity = useSettingsStore((state) => state.autoSelectReplyIdentity);
|
||||
const attachmentReminderEnabled = useSettingsStore((state) => state.attachmentReminderEnabled);
|
||||
const attachmentReminderKeywords = useSettingsStore((state) => state.attachmentReminderKeywords);
|
||||
|
||||
// Initialize with reply/forward data if provided
|
||||
const getInitialTo = () => {
|
||||
@@ -212,6 +214,8 @@ export function EmailComposer({
|
||||
const [smimePassphrasePrompt, setSmimePassphrasePrompt] = useState<{ keyId: string; resolve: (passphrase: string) => void; reject: () => void } | null>(null);
|
||||
const [smimePassphraseInput, setSmimePassphraseInput] = useState('');
|
||||
const [smimePassphraseError, setSmimePassphraseError] = useState('');
|
||||
const [showAttachmentWarning, setShowAttachmentWarning] = useState(false);
|
||||
const [attachmentWarningKeyword, setAttachmentWarningKeyword] = useState('');
|
||||
|
||||
const saveTemplateModalRef = useFocusTrap({
|
||||
isActive: showSaveAsTemplate,
|
||||
@@ -225,6 +229,12 @@ export function EmailComposer({
|
||||
restoreFocus: true,
|
||||
});
|
||||
|
||||
const attachmentWarningRef = useFocusTrap({
|
||||
isActive: showAttachmentWarning,
|
||||
onEscape: () => setShowAttachmentWarning(false),
|
||||
restoreFocus: true,
|
||||
});
|
||||
|
||||
const { client } = useAuthStore();
|
||||
const identities = useIdentityStore((s) => s.identities);
|
||||
const primaryIdentity = identities[0] ?? null;
|
||||
@@ -723,7 +733,7 @@ export function EmailComposer({
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const handleSend = async () => {
|
||||
const handleSend = async (skipAttachmentCheck = false) => {
|
||||
const ccAddresses = cc.split(",").map(e => e.trim()).filter(Boolean);
|
||||
const bccAddresses = bcc.split(",").map(e => e.trim()).filter(Boolean);
|
||||
|
||||
@@ -742,6 +752,21 @@ export function EmailComposer({
|
||||
return;
|
||||
}
|
||||
|
||||
// Attachment reminder check
|
||||
if (!skipAttachmentCheck && attachmentReminderEnabled) {
|
||||
const hasAttachments = attachments.some(att => att.blobId && !att.uploading && !att.error);
|
||||
if (!hasAttachments) {
|
||||
const bodyText = htmlToPlainText(body);
|
||||
const searchText = `${subject} ${bodyText}`.toLowerCase();
|
||||
const matched = attachmentReminderKeywords.find(kw => searchText.includes(kw.toLowerCase()));
|
||||
if (matched) {
|
||||
setAttachmentWarningKeyword(matched);
|
||||
setShowAttachmentWarning(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let finalDraftId = draftId;
|
||||
if (saveTimeoutRef.current) {
|
||||
clearTimeout(saveTimeoutRef.current);
|
||||
@@ -1002,7 +1027,7 @@ export function EmailComposer({
|
||||
</div>
|
||||
{/* Mobile: send button in header */}
|
||||
<Button
|
||||
onClick={handleSend}
|
||||
onClick={() => handleSend()}
|
||||
disabled={!canSend}
|
||||
title={getSendTooltip()}
|
||||
size="sm"
|
||||
@@ -1367,7 +1392,7 @@ export function EmailComposer({
|
||||
{t('discard')}
|
||||
</button>
|
||||
<Button
|
||||
onClick={handleSend}
|
||||
onClick={() => handleSend()}
|
||||
disabled={!canSend}
|
||||
title={getSendTooltip()}
|
||||
className="hidden md:inline-flex"
|
||||
@@ -1467,6 +1492,36 @@ export function EmailComposer({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showAttachmentWarning && (
|
||||
<div
|
||||
className="fixed inset-0 bg-black/50 backdrop-blur-[1px] flex items-center justify-center z-[60] p-4 animate-in fade-in duration-150"
|
||||
onClick={() => setShowAttachmentWarning(false)}
|
||||
>
|
||||
<div
|
||||
ref={attachmentWarningRef}
|
||||
role="alertdialog"
|
||||
aria-modal="true"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="bg-background border border-border rounded-lg shadow-xl w-full max-w-md animate-in zoom-in-95 duration-200"
|
||||
>
|
||||
<div className="p-6">
|
||||
<h2 className="text-lg font-semibold text-foreground">{t('forgot_attachment.title')}</h2>
|
||||
<p className="mt-2 text-sm text-muted-foreground">
|
||||
{t('forgot_attachment.message', { keyword: attachmentWarningKeyword })}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-end gap-3 px-6 pb-6">
|
||||
<Button variant="outline" onClick={() => setShowAttachmentWarning(false)}>
|
||||
{t('forgot_attachment.back')}
|
||||
</Button>
|
||||
<Button onClick={() => { setShowAttachmentWarning(false); handleSend(true); }}>
|
||||
{t('forgot_attachment.send_anyway')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showCloseDialog && (
|
||||
<div
|
||||
className="fixed inset-0 bg-black/50 backdrop-blur-[1px] flex items-center justify-center z-[60] p-4 animate-in fade-in duration-150"
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useEmailStore } from '@/stores/email-store';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { RadioGroup, SettingsSection, SettingItem, Select, ToggleSwitch } from './settings-section';
|
||||
import { TrustedSendersModal } from '@/components/trusted-senders-modal';
|
||||
import { ChevronRight, AlertTriangle, FolderSync, Loader2, Mail } from 'lucide-react';
|
||||
import { ChevronRight, AlertTriangle, FolderSync, Loader2, Mail, X } from 'lucide-react';
|
||||
import { usePolicyStore } from '@/stores/policy-store';
|
||||
|
||||
const MAIL_LAYOUT_PREVIEW_ROWS = [
|
||||
@@ -110,6 +110,8 @@ export function EmailSettings() {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const [newKeyword, setNewKeyword] = useState('');
|
||||
|
||||
const {
|
||||
markAsReadDelay,
|
||||
deleteAction,
|
||||
@@ -129,6 +131,8 @@ export function EmailSettings() {
|
||||
hoverActionsMode,
|
||||
hoverActionsCorner,
|
||||
trustedSenders,
|
||||
attachmentReminderEnabled,
|
||||
attachmentReminderKeywords,
|
||||
updateSetting,
|
||||
} = useSettingsStore();
|
||||
|
||||
@@ -337,6 +341,63 @@ export function EmailSettings() {
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
{/* Attachment Reminder */}
|
||||
<SettingItem label={t('attachment_reminder.label')} description={t('attachment_reminder.description')}>
|
||||
<ToggleSwitch
|
||||
checked={attachmentReminderEnabled}
|
||||
onChange={(checked) => updateSetting('attachmentReminderEnabled', checked)}
|
||||
/>
|
||||
</SettingItem>
|
||||
{attachmentReminderEnabled && (
|
||||
<div className="py-3 border-b border-border space-y-2">
|
||||
<div>
|
||||
<label className="text-sm font-medium text-foreground">{t('attachment_reminder.keywords_label')}</label>
|
||||
<p className="text-xs text-muted-foreground mt-1">{t('attachment_reminder.keywords_description')}</p>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{attachmentReminderKeywords.map((kw) => (
|
||||
<span key={kw} className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs bg-muted text-foreground">
|
||||
{kw}
|
||||
<button
|
||||
type="button"
|
||||
aria-label={t('attachment_reminder.remove')}
|
||||
onClick={() => updateSetting('attachmentReminderKeywords', attachmentReminderKeywords.filter(k => k !== kw))}
|
||||
className="text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<X className="w-3 h-3" />
|
||||
</button>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<form
|
||||
className="flex gap-2"
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
const trimmed = newKeyword.trim().toLowerCase();
|
||||
if (trimmed && !attachmentReminderKeywords.includes(trimmed)) {
|
||||
updateSetting('attachmentReminderKeywords', [...attachmentReminderKeywords, trimmed]);
|
||||
}
|
||||
setNewKeyword('');
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
value={newKeyword}
|
||||
onChange={(e) => setNewKeyword(e.target.value)}
|
||||
placeholder={t('attachment_reminder.add_placeholder')}
|
||||
className="flex-1 min-w-0 px-2 py-1 text-sm bg-background border border-border rounded-md focus:outline-none focus:ring-1 focus:ring-ring"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!newKeyword.trim()}
|
||||
className="px-3 py-1 text-sm bg-muted hover:bg-accent rounded-md disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{t('attachment_reminder.add')}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Quick Hover Actions */}
|
||||
{isFeatureEnabled('hoverActionsConfigEnabled') && (
|
||||
<div className="py-3 border-b border-border space-y-3">
|
||||
|
||||
+16
-1
@@ -494,7 +494,13 @@
|
||||
"close_draft_message": "Sie haben ungespeicherte Änderungen. Möchten Sie diese als Entwurf speichern oder verwerfen?",
|
||||
"save_draft": "Entwurf speichern",
|
||||
"drop_files": "Dateien zum Anhängen ablegen",
|
||||
"show_less": "Weniger anzeigen"
|
||||
"show_less": "Weniger anzeigen",
|
||||
"forgot_attachment": {
|
||||
"title": "Haben Sie den Anhang vergessen?",
|
||||
"message": "Ihre Nachricht enthält \"{keyword}\", aber es ist keine Datei angehängt. Trotzdem senden?",
|
||||
"send_anyway": "Trotzdem senden",
|
||||
"back": "Zurück zur Bearbeitung"
|
||||
}
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Bestätigen",
|
||||
@@ -914,6 +920,15 @@
|
||||
"button": "Als Standard festlegen",
|
||||
"success": "Browser wurde aufgefordert, als Standard festzulegen",
|
||||
"error": "Ihr Browser unterstützt diese Funktion nicht"
|
||||
},
|
||||
"attachment_reminder": {
|
||||
"label": "Erinnerung an Anhang",
|
||||
"description": "Warnung anzeigen, wenn die Nachricht Anhänge erwähnt, aber keine angehängt sind",
|
||||
"keywords_label": "Schlüsselwörter",
|
||||
"keywords_description": "Wörter oder Phrasen, die die Erinnerung auslösen",
|
||||
"add_placeholder": "Schlüsselwort hinzufügen...",
|
||||
"add": "Hinzufügen",
|
||||
"remove": "Entfernen"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
|
||||
+16
-1
@@ -494,7 +494,13 @@
|
||||
"smime_unlock_title": "Unlock S/MIME Key",
|
||||
"smime_unlock_message": "Enter the passphrase to unlock your S/MIME signing key.",
|
||||
"smime_unlock_button": "Unlock",
|
||||
"smime_passphrase_placeholder": "Passphrase"
|
||||
"smime_passphrase_placeholder": "Passphrase",
|
||||
"forgot_attachment": {
|
||||
"title": "Did you forget an attachment?",
|
||||
"message": "Your message mentions \"{keyword}\" but no file is attached. Send anyway?",
|
||||
"send_anyway": "Send anyway",
|
||||
"back": "Back to editing"
|
||||
}
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Confirm",
|
||||
@@ -914,6 +920,15 @@
|
||||
"button": "Set as Default",
|
||||
"success": "Browser prompted to set as default",
|
||||
"error": "Your browser does not support this feature"
|
||||
},
|
||||
"attachment_reminder": {
|
||||
"label": "Attachment Reminder",
|
||||
"description": "Warn before sending when your message mentions attachments but none are attached",
|
||||
"keywords_label": "Trigger keywords",
|
||||
"keywords_description": "Words or phrases that trigger the reminder when found in your message",
|
||||
"add_placeholder": "Add keyword...",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
|
||||
+16
-1
@@ -494,7 +494,13 @@
|
||||
"close_draft_message": "Tiene cambios sin guardar. ¿Desea guardar esto como borrador o descartarlo?",
|
||||
"save_draft": "Guardar borrador",
|
||||
"drop_files": "Suelta archivos para adjuntar",
|
||||
"show_less": "Mostrar menos"
|
||||
"show_less": "Mostrar menos",
|
||||
"forgot_attachment": {
|
||||
"title": "Did you forget an attachment?",
|
||||
"message": "Your message mentions \"{keyword}\" but no file is attached. Send anyway?",
|
||||
"send_anyway": "Send anyway",
|
||||
"back": "Back to editing"
|
||||
}
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Confirmar",
|
||||
@@ -914,6 +920,15 @@
|
||||
"button": "Establecer como predeterminado",
|
||||
"success": "El navegador solicitó establecer como predeterminado",
|
||||
"error": "Su navegador no admite esta función"
|
||||
},
|
||||
"attachment_reminder": {
|
||||
"label": "Attachment Reminder",
|
||||
"description": "Warn before sending when your message mentions attachments but none are attached",
|
||||
"keywords_label": "Trigger keywords",
|
||||
"keywords_description": "Words or phrases that trigger the reminder when found in your message",
|
||||
"add_placeholder": "Add keyword...",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
|
||||
+16
-1
@@ -494,7 +494,13 @@
|
||||
"close_draft_message": "Vous avez des modifications non enregistrées. Voulez-vous enregistrer comme brouillon ou supprimer ?",
|
||||
"save_draft": "Enregistrer le brouillon",
|
||||
"drop_files": "Déposez les fichiers à joindre",
|
||||
"show_less": "Afficher moins"
|
||||
"show_less": "Afficher moins",
|
||||
"forgot_attachment": {
|
||||
"title": "Did you forget an attachment?",
|
||||
"message": "Your message mentions \"{keyword}\" but no file is attached. Send anyway?",
|
||||
"send_anyway": "Send anyway",
|
||||
"back": "Back to editing"
|
||||
}
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Confirmer",
|
||||
@@ -914,6 +920,15 @@
|
||||
"button": "Définir par défaut",
|
||||
"success": "Le navigateur a été invité à définir par défaut",
|
||||
"error": "Votre navigateur ne prend pas en charge cette fonctionnalité"
|
||||
},
|
||||
"attachment_reminder": {
|
||||
"label": "Attachment Reminder",
|
||||
"description": "Warn before sending when your message mentions attachments but none are attached",
|
||||
"keywords_label": "Trigger keywords",
|
||||
"keywords_description": "Words or phrases that trigger the reminder when found in your message",
|
||||
"add_placeholder": "Add keyword...",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
|
||||
+16
-1
@@ -494,7 +494,13 @@
|
||||
"close_draft_message": "Hai modifiche non salvate. Vuoi salvare come bozza o eliminare?",
|
||||
"save_draft": "Salva bozza",
|
||||
"drop_files": "Trascina i file per allegarli",
|
||||
"show_less": "Mostra meno"
|
||||
"show_less": "Mostra meno",
|
||||
"forgot_attachment": {
|
||||
"title": "Did you forget an attachment?",
|
||||
"message": "Your message mentions \"{keyword}\" but no file is attached. Send anyway?",
|
||||
"send_anyway": "Send anyway",
|
||||
"back": "Back to editing"
|
||||
}
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Conferma",
|
||||
@@ -914,6 +920,15 @@
|
||||
"button": "Imposta come predefinito",
|
||||
"success": "Il browser ha chiesto di impostare come predefinito",
|
||||
"error": "Il tuo browser non supporta questa funzionalità"
|
||||
},
|
||||
"attachment_reminder": {
|
||||
"label": "Attachment Reminder",
|
||||
"description": "Warn before sending when your message mentions attachments but none are attached",
|
||||
"keywords_label": "Trigger keywords",
|
||||
"keywords_description": "Words or phrases that trigger the reminder when found in your message",
|
||||
"add_placeholder": "Add keyword...",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
|
||||
+16
-1
@@ -494,7 +494,13 @@
|
||||
"close_draft_message": "未保存の変更があります。下書きとして保存しますか、それとも破棄しますか?",
|
||||
"save_draft": "下書きを保存",
|
||||
"drop_files": "ファイルをドロップして添付",
|
||||
"show_less": "折りたたむ"
|
||||
"show_less": "折りたたむ",
|
||||
"forgot_attachment": {
|
||||
"title": "Did you forget an attachment?",
|
||||
"message": "Your message mentions \"{keyword}\" but no file is attached. Send anyway?",
|
||||
"send_anyway": "Send anyway",
|
||||
"back": "Back to editing"
|
||||
}
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "確認",
|
||||
@@ -914,6 +920,15 @@
|
||||
"button": "既定に設定",
|
||||
"success": "ブラウザに既定として設定するよう要求しました",
|
||||
"error": "お使いのブラウザはこの機能をサポートしていません"
|
||||
},
|
||||
"attachment_reminder": {
|
||||
"label": "Attachment Reminder",
|
||||
"description": "Warn before sending when your message mentions attachments but none are attached",
|
||||
"keywords_label": "Trigger keywords",
|
||||
"keywords_description": "Words or phrases that trigger the reminder when found in your message",
|
||||
"add_placeholder": "Add keyword...",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
|
||||
+16
-1
@@ -494,7 +494,13 @@
|
||||
"smime_unlock_title": "S/MIME 키 잠금 해제",
|
||||
"smime_unlock_message": "S/MIME 서명 키의 잠금을 해제하려면 비밀번호를 입력해 주세요.",
|
||||
"smime_unlock_button": "잠금 해제",
|
||||
"smime_passphrase_placeholder": "비밀번호"
|
||||
"smime_passphrase_placeholder": "비밀번호",
|
||||
"forgot_attachment": {
|
||||
"title": "Did you forget an attachment?",
|
||||
"message": "Your message mentions \"{keyword}\" but no file is attached. Send anyway?",
|
||||
"send_anyway": "Send anyway",
|
||||
"back": "Back to editing"
|
||||
}
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "확인",
|
||||
@@ -914,6 +920,15 @@
|
||||
"button": "기본값으로 설정",
|
||||
"success": "브라우저에서 기본 설정 팝업이 뜰 거예요",
|
||||
"error": "이 브라우저에서는 이 기능을 지원하지 않아요"
|
||||
},
|
||||
"attachment_reminder": {
|
||||
"label": "Attachment Reminder",
|
||||
"description": "Warn before sending when your message mentions attachments but none are attached",
|
||||
"keywords_label": "Trigger keywords",
|
||||
"keywords_description": "Words or phrases that trigger the reminder when found in your message",
|
||||
"add_placeholder": "Add keyword...",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
|
||||
+16
-1
@@ -493,7 +493,13 @@
|
||||
"smime_unlock_title": "Atbloķēt S/MIME atslēgu",
|
||||
"smime_unlock_message": "Ievadiet paroli, lai atbloķētu savu S/MIME parakstīšanas atslēgu.",
|
||||
"smime_unlock_button": "Atbloķēt",
|
||||
"smime_passphrase_placeholder": "Parole"
|
||||
"smime_passphrase_placeholder": "Parole",
|
||||
"forgot_attachment": {
|
||||
"title": "Did you forget an attachment?",
|
||||
"message": "Your message mentions \"{keyword}\" but no file is attached. Send anyway?",
|
||||
"send_anyway": "Send anyway",
|
||||
"back": "Back to editing"
|
||||
}
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Apstiprināt",
|
||||
@@ -913,6 +919,15 @@
|
||||
"button": "Iestatīt kā noklusējumu",
|
||||
"success": "Pārlūkam nosūtīts pieprasījums iestatīt kā noklusējumu",
|
||||
"error": "Jūsu pārlūks neatbalsta šo funkciju"
|
||||
},
|
||||
"attachment_reminder": {
|
||||
"label": "Attachment Reminder",
|
||||
"description": "Warn before sending when your message mentions attachments but none are attached",
|
||||
"keywords_label": "Trigger keywords",
|
||||
"keywords_description": "Words or phrases that trigger the reminder when found in your message",
|
||||
"add_placeholder": "Add keyword...",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
|
||||
+16
-1
@@ -494,7 +494,13 @@
|
||||
"close_draft_message": "U heeft niet-opgeslagen wijzigingen. Wilt u dit als concept opslaan of verwijderen?",
|
||||
"save_draft": "Concept opslaan",
|
||||
"drop_files": "Sleep bestanden om bij te voegen",
|
||||
"show_less": "Minder tonen"
|
||||
"show_less": "Minder tonen",
|
||||
"forgot_attachment": {
|
||||
"title": "Did you forget an attachment?",
|
||||
"message": "Your message mentions \"{keyword}\" but no file is attached. Send anyway?",
|
||||
"send_anyway": "Send anyway",
|
||||
"back": "Back to editing"
|
||||
}
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Bevestigen",
|
||||
@@ -914,6 +920,15 @@
|
||||
"button": "Instellen als standaard",
|
||||
"success": "Browser gevraagd om als standaard in te stellen",
|
||||
"error": "Uw browser ondersteunt deze functie niet"
|
||||
},
|
||||
"attachment_reminder": {
|
||||
"label": "Attachment Reminder",
|
||||
"description": "Warn before sending when your message mentions attachments but none are attached",
|
||||
"keywords_label": "Trigger keywords",
|
||||
"keywords_description": "Words or phrases that trigger the reminder when found in your message",
|
||||
"add_placeholder": "Add keyword...",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
|
||||
+16
-1
@@ -494,7 +494,13 @@
|
||||
"smime_unlock_title": "Odblokuj klucz S/MIME",
|
||||
"smime_unlock_message": "Wprowadź hasło, aby odblokować klucz podpisywania S/MIME.",
|
||||
"smime_unlock_button": "Odblokuj",
|
||||
"smime_passphrase_placeholder": "Hasło"
|
||||
"smime_passphrase_placeholder": "Hasło",
|
||||
"forgot_attachment": {
|
||||
"title": "Did you forget an attachment?",
|
||||
"message": "Your message mentions \"{keyword}\" but no file is attached. Send anyway?",
|
||||
"send_anyway": "Send anyway",
|
||||
"back": "Back to editing"
|
||||
}
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Potwierdź",
|
||||
@@ -916,6 +922,15 @@
|
||||
"button": "Ustaw jako domyślny",
|
||||
"success": "Przeglądarka poprosiła o ustawienie jako domyślnego",
|
||||
"error": "Twoja przeglądarka nie obsługuje tej funkcji"
|
||||
},
|
||||
"attachment_reminder": {
|
||||
"label": "Attachment Reminder",
|
||||
"description": "Warn before sending when your message mentions attachments but none are attached",
|
||||
"keywords_label": "Trigger keywords",
|
||||
"keywords_description": "Words or phrases that trigger the reminder when found in your message",
|
||||
"add_placeholder": "Add keyword...",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
|
||||
+16
-1
@@ -494,7 +494,13 @@
|
||||
"close_draft_message": "Você tem alterações não salvas. Deseja salvar como rascunho ou descartar?",
|
||||
"save_draft": "Salvar rascunho",
|
||||
"drop_files": "Solte arquivos para anexar",
|
||||
"show_less": "Mostrar menos"
|
||||
"show_less": "Mostrar menos",
|
||||
"forgot_attachment": {
|
||||
"title": "Did you forget an attachment?",
|
||||
"message": "Your message mentions \"{keyword}\" but no file is attached. Send anyway?",
|
||||
"send_anyway": "Send anyway",
|
||||
"back": "Back to editing"
|
||||
}
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Confirmar",
|
||||
@@ -914,6 +920,15 @@
|
||||
"button": "Definir como padrão",
|
||||
"success": "O navegador solicitou definir como padrão",
|
||||
"error": "Seu navegador não suporta esta funcionalidade"
|
||||
},
|
||||
"attachment_reminder": {
|
||||
"label": "Attachment Reminder",
|
||||
"description": "Warn before sending when your message mentions attachments but none are attached",
|
||||
"keywords_label": "Trigger keywords",
|
||||
"keywords_description": "Words or phrases that trigger the reminder when found in your message",
|
||||
"add_placeholder": "Add keyword...",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
|
||||
+16
-1
@@ -494,7 +494,13 @@
|
||||
"smime_unlock_title": "Разблокировать ключ S/MIME",
|
||||
"smime_unlock_message": "Введите парольную фразу для разблокировки вашего ключа подписи S/MIME.",
|
||||
"smime_unlock_button": "Разблокировать",
|
||||
"smime_passphrase_placeholder": "Парольная фраза"
|
||||
"smime_passphrase_placeholder": "Парольная фраза",
|
||||
"forgot_attachment": {
|
||||
"title": "Did you forget an attachment?",
|
||||
"message": "Your message mentions \"{keyword}\" but no file is attached. Send anyway?",
|
||||
"send_anyway": "Send anyway",
|
||||
"back": "Back to editing"
|
||||
}
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "Подтвердить",
|
||||
@@ -914,6 +920,15 @@
|
||||
"button": "Установить по умолчанию",
|
||||
"success": "Браузер запрошен для установки по умолчанию",
|
||||
"error": "Ваш браузер не поддерживает эту функцию"
|
||||
},
|
||||
"attachment_reminder": {
|
||||
"label": "Attachment Reminder",
|
||||
"description": "Warn before sending when your message mentions attachments but none are attached",
|
||||
"keywords_label": "Trigger keywords",
|
||||
"keywords_description": "Words or phrases that trigger the reminder when found in your message",
|
||||
"add_placeholder": "Add keyword...",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
|
||||
+16
-1
@@ -494,7 +494,13 @@
|
||||
"smime_unlock_title": "解锁 S/MIME 密钥",
|
||||
"smime_unlock_message": "输入密码以解锁您的 S/MIME 签名密钥。",
|
||||
"smime_unlock_button": "解锁",
|
||||
"smime_passphrase_placeholder": "输入密码"
|
||||
"smime_passphrase_placeholder": "输入密码",
|
||||
"forgot_attachment": {
|
||||
"title": "Did you forget an attachment?",
|
||||
"message": "Your message mentions \"{keyword}\" but no file is attached. Send anyway?",
|
||||
"send_anyway": "Send anyway",
|
||||
"back": "Back to editing"
|
||||
}
|
||||
},
|
||||
"confirm_dialog": {
|
||||
"confirm": "确认",
|
||||
@@ -914,6 +920,15 @@
|
||||
"button": "设为默认",
|
||||
"success": "浏览器已提示设置为默认",
|
||||
"error": "您的浏览器不支持此功能"
|
||||
},
|
||||
"attachment_reminder": {
|
||||
"label": "Attachment Reminder",
|
||||
"description": "Warn before sending when your message mentions attachments but none are attached",
|
||||
"keywords_label": "Trigger keywords",
|
||||
"keywords_description": "Words or phrases that trigger the reminder when found in your message",
|
||||
"add_placeholder": "Add keyword...",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
|
||||
@@ -185,6 +185,10 @@ interface SettingsState {
|
||||
// Keywords (labels/tags)
|
||||
emailKeywords: KeywordDefinition[];
|
||||
|
||||
// Attachment Reminder
|
||||
attachmentReminderEnabled: boolean;
|
||||
attachmentReminderKeywords: string[];
|
||||
|
||||
// Sidebar Apps
|
||||
sidebarApps: SidebarApp[];
|
||||
keepAppsLoaded: boolean;
|
||||
@@ -314,6 +318,37 @@ const DEFAULT_SETTINGS = {
|
||||
// Keywords
|
||||
emailKeywords: DEFAULT_KEYWORDS,
|
||||
|
||||
// Attachment Reminder
|
||||
attachmentReminderEnabled: true,
|
||||
attachmentReminderKeywords: [
|
||||
// English
|
||||
'attached', 'attachment', 'attachments', 'see attached', 'find attached', 'please find attached',
|
||||
// German
|
||||
'angehängt', 'anhang', 'anbei', 'im anhang',
|
||||
// French
|
||||
'ci-joint', 'pièce jointe',
|
||||
// Spanish
|
||||
'adjunto', 'adjunta', 'en adjunto',
|
||||
// Italian
|
||||
'allegato', 'in allegato',
|
||||
// Dutch
|
||||
'bijgevoegd', 'bijlage',
|
||||
// Portuguese
|
||||
'em anexo', 'anexo',
|
||||
// Polish
|
||||
'w załączniku',
|
||||
// Russian
|
||||
'во вложении',
|
||||
// Japanese
|
||||
'添付',
|
||||
// Chinese
|
||||
'附件',
|
||||
// Korean
|
||||
'첨부',
|
||||
// Latvian
|
||||
'pielikumā',
|
||||
] as string[],
|
||||
|
||||
// Sidebar Apps
|
||||
sidebarApps: [] as SidebarApp[],
|
||||
keepAppsLoaded: false,
|
||||
@@ -412,6 +447,8 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
senderFavicons: state.senderFavicons,
|
||||
folderIcons: state.folderIcons,
|
||||
emailKeywords: state.emailKeywords,
|
||||
attachmentReminderEnabled: state.attachmentReminderEnabled,
|
||||
attachmentReminderKeywords: state.attachmentReminderKeywords,
|
||||
sidebarApps: state.sidebarApps,
|
||||
keepAppsLoaded: state.keepAppsLoaded,
|
||||
debugMode: state.debugMode,
|
||||
|
||||
Reference in New Issue
Block a user