)}
@@ -824,6 +832,9 @@ export function FilterSettings() {
regexSupported={supportsRegex(sieveCapabilities?.sieveExtensions)}
forwardsBefore={forwardsOfEdited.before}
forwardsAfter={forwardsOfEdited.after}
+ offerApplyToExisting={!!inboxOffer}
+ applyExistingFolder={inboxOffer?.folder}
+ countExisting={inboxOffer ? countInInbox : undefined}
onSave={handleSaveRule}
onClose={() => {
setShowRuleModal(false);
diff --git a/lib/filters/quick-rule-flow.ts b/lib/filters/quick-rule-flow.ts
index 9628f48b8..d49a85eba 100644
--- a/lib/filters/quick-rule-flow.ts
+++ b/lib/filters/quick-rule-flow.ts
@@ -213,30 +213,6 @@ async function applyAndReport(
}
}
-/**
- * After a rule was saved in Settings › Filters: when it would change mail
- * already in `mailboxId` (the Inbox), say how much and offer to apply it
- * there. Nothing is said when it would change nothing or can't be checked.
- */
-export async function offerRuleOnFolder(
- target: QuickRuleTarget,
- rule: FilterRule,
- mailboxId: string,
- text: QuickRuleText,
- applyLabel: (count: number) => string,
-): Promise {
- const plan = await planSafely(target, rule, mailboxId);
- if (plan.ids.length === 0) return;
- toast.success(text.notifications('rule_created'), {
- message: rule.name,
- duration: SAVED_TOAST_MS,
- action: {
- label: applyLabel(plan.ids.length),
- onClick: () => { void applyAndReport(target, rule, mailboxId, text); },
- },
- });
-}
-
/**
* Run a saved rule over the mail already in a folder, from the folder's
* context menu. A progress toast stays up while the server is asked which
diff --git a/locales/ar/common.json b/locales/ar/common.json
index 999cafaf0..1bd640de3 100644
--- a/locales/ar/common.json
+++ b/locales/ar/common.json
@@ -2913,6 +2913,7 @@
"open_sieve_editor": "فتح محرر Sieve الخام",
"fetch_error": "فشل تحميل المرشحات",
"expanded_view": "عرض موسّع",
+ "show_rule_details": "عرض شروط كل قاعدة وإجراءاتها",
"expanded_view_description": "إظهار قواعد المرشح مع كتل الشروط والإجراءات المفصّلة",
"if": "إذا",
"then": "عندئذٍ",
@@ -2991,6 +2992,9 @@
"validation_period_empty": "أدخل تاريخ بدء أو انتهاء للفترة",
"validation_period_invalid": "أدخل تاريخًا صالحًا مع الوقت للفترة، أو اترك الحقل فارغًا",
"apply_existing_period": "القاعدة ذات الفترة الزمنية تعمل فقط على الرسائل التي تصل خلالها، لذا لا يمكن تطبيقها على الرسائل الموجودة.",
+ "apply_existing_in": "طبّقها أيضًا على الرسائل الموجودة في {folder}",
+ "apply_existing_count": "{count, plural, zero {طبّقها أيضًا على الرسائل الموجودة في {folder}} one {طبّقها أيضًا على الرسالة الموجودة في {folder}} two {طبّقها أيضًا على الرسالتين الموجودتين في {folder}} few {طبّقها أيضًا على # رسائل موجودة في {folder}} many {طبّقها أيضًا على # رسالة موجودة في {folder}} other {طبّقها أيضًا على # رسالة موجودة في {folder}}}",
+ "apply_existing_none": "لا توجد رسالة في {folder} تطابق هذه القاعدة بعد.",
"period_status_scheduled": "مجدولة",
"period_status_active": "نشطة",
"period_status_expired": "منتهية"
diff --git a/locales/ca/common.json b/locales/ca/common.json
index 091cd601c..1d5b3f23c 100644
--- a/locales/ca/common.json
+++ b/locales/ca/common.json
@@ -2913,6 +2913,7 @@
"open_sieve_editor": "Obre l'editor Sieve en brut",
"fetch_error": "No s'han pogut carregar els filtres",
"expanded_view": "Vista ampliada",
+ "show_rule_details": "Mostra les condicions i les accions de cada regla",
"expanded_view_description": "Mostra les regles de filtre amb blocs detallats de condicions i accions",
"if": "Si",
"then": "Aleshores",
@@ -2991,6 +2992,9 @@
"validation_period_empty": "Introdueix una data d'inici o de finalització per al període",
"validation_period_invalid": "Introdueix una data vàlida amb l'hora per al període, o deixa el camp buit",
"apply_existing_period": "Una regla amb període només actua sobre els missatges que arriben dins d'aquest període, de manera que no es pot aplicar als missatges existents.",
+ "apply_existing_in": "Aplica-la també als missatges que ja són a {folder}",
+ "apply_existing_count": "{count, plural, one {Aplica-la també al # missatge que ja és a {folder}} other {Aplica-la també als # missatges que ja són a {folder}}}",
+ "apply_existing_none": "Encara cap missatge de {folder} no compleix aquesta regla.",
"period_status_scheduled": "programada",
"period_status_active": "activa",
"period_status_expired": "caducada"
diff --git a/locales/cs/common.json b/locales/cs/common.json
index b2ae541cf..0b2185b9f 100644
--- a/locales/cs/common.json
+++ b/locales/cs/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "Otevřít textový editor Sieve",
"fetch_error": "Nepodařilo se načíst filtry",
"expanded_view": "Rozšířené zobrazení",
+ "show_rule_details": "Zobrazit podmínky a akce každého pravidla",
"expanded_view_description": "Zobrazovat pravidla filtrů s podrobnými bloky podmínek a akcí",
"if": "Pokud",
"then": "Pak",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "Zadejte datum zahájení nebo ukončení období",
"validation_period_invalid": "Zadejte pro období platné datum včetně času, nebo pole nechte prázdné",
"apply_existing_period": "Pravidlo s obdobím působí jen na zprávy, které v něm přijdou, a proto ho nelze použít na existující zprávy.",
+ "apply_existing_in": "Použít i na zprávy, které už jsou ve složce {folder}",
+ "apply_existing_count": "{count, plural, one {Použít i na # zprávu, která už je ve složce {folder}} few {Použít i na # zprávy, které už jsou ve složce {folder}} many {Použít i na # zprávy, které už jsou ve složce {folder}} other {Použít i na # zpráv, které už jsou ve složce {folder}}}",
+ "apply_existing_none": "Tomuto pravidlu zatím neodpovídá žádná zpráva ve složce {folder}.",
"period_status_scheduled": "naplánováno",
"period_status_active": "aktivní",
"period_status_expired": "vypršelo"
diff --git a/locales/da/common.json b/locales/da/common.json
index 7d48f4b15..c851d2dff 100644
--- a/locales/da/common.json
+++ b/locales/da/common.json
@@ -2909,6 +2909,7 @@
"open_sieve_editor": "Åbn raw Sieve-editor",
"fetch_error": "Kunne ikke indlæse filtre",
"expanded_view": "Udvidet visning",
+ "show_rule_details": "Vis hver regels betingelser og handlinger",
"expanded_view_description": "Vis filterregler med detaljerede betingelses- og handlingsblokke",
"if": "Hvis",
"then": "Så",
@@ -2987,6 +2988,9 @@
"validation_period_empty": "Angiv en start- eller slutdato for perioden",
"validation_period_invalid": "Angiv en gyldig dato med klokkeslæt for perioden, eller lad feltet stå tomt",
"apply_existing_period": "En regel med en periode virker kun på beskeder, der ankommer i perioden, og kan derfor ikke køres på eksisterende beskeder.",
+ "apply_existing_in": "Anvend også på beskederne, der allerede er i {folder}",
+ "apply_existing_count": "{count, plural, one {Anvend også på den # besked, der allerede er i {folder}} other {Anvend også på de # beskeder, der allerede er i {folder}}}",
+ "apply_existing_none": "Ingen beskeder i {folder} passer til reglen endnu.",
"period_status_scheduled": "planlagt",
"period_status_active": "aktiv",
"period_status_expired": "udløbet"
diff --git a/locales/de/common.json b/locales/de/common.json
index e1e33c934..3bc9f148f 100644
--- a/locales/de/common.json
+++ b/locales/de/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "Sieve-Skript-Editor öffnen",
"fetch_error": "Filter konnten nicht geladen werden",
"expanded_view": "Erweiterte Ansicht",
+ "show_rule_details": "Bedingungen und Aktionen jeder Regel anzeigen",
"expanded_view_description": "Filterregeln mit detaillierten Bedingungs- und Aktionsblöcken anzeigen",
"if": "Wenn",
"then": "Dann",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "Bitte ein Start- oder Enddatum für den Zeitraum angeben",
"validation_period_invalid": "Bitte für den Zeitraum ein gültiges Datum mit Uhrzeit angeben oder das Feld leer lassen",
"apply_existing_period": "Eine Regel mit Zeitraum wirkt nur auf Nachrichten, die in diesem Zeitraum eintreffen, und lässt sich daher nicht auf vorhandene Nachrichten anwenden.",
+ "apply_existing_in": "Auch auf die Nachrichten anwenden, die schon in {folder} sind",
+ "apply_existing_count": "{count, plural, one {Auch auf die # Nachricht anwenden, die schon in {folder} ist} other {Auch auf die # Nachrichten anwenden, die schon in {folder} sind}}",
+ "apply_existing_none": "Noch keine Nachricht in {folder} passt zu dieser Regel.",
"period_status_scheduled": "geplant",
"period_status_active": "aktiv",
"period_status_expired": "abgelaufen"
diff --git a/locales/en/common.json b/locales/en/common.json
index ae08611b3..1582cb279 100644
--- a/locales/en/common.json
+++ b/locales/en/common.json
@@ -2913,6 +2913,7 @@
"open_sieve_editor": "Open raw Sieve editor",
"fetch_error": "Couldn't load the filters",
"expanded_view": "Expanded view",
+ "show_rule_details": "Show each rule’s conditions and actions",
"expanded_view_description": "Show filter rules with detailed condition and action blocks",
"if": "If",
"then": "Then",
@@ -2991,6 +2992,9 @@
"validation_period_empty": "Enter a start or end date for the period",
"validation_period_invalid": "Enter a valid date with a time for the period, or leave the field empty",
"apply_existing_period": "A rule with a period acts only on messages that arrive within it, so it cannot run on existing messages.",
+ "apply_existing_in": "Also apply to the messages already in {folder}",
+ "apply_existing_count": "{count, plural, one {Also apply to the # message already in {folder}} other {Also apply to the # messages already in {folder}}}",
+ "apply_existing_none": "No message in {folder} matches this rule yet.",
"period_status_scheduled": "scheduled",
"period_status_active": "active",
"period_status_expired": "expired"
diff --git a/locales/es/common.json b/locales/es/common.json
index e4c6f39e9..d44f166af 100644
--- a/locales/es/common.json
+++ b/locales/es/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "Abrir editor Sieve",
"fetch_error": "Error al cargar los filtros",
"expanded_view": "Vista expandida",
+ "show_rule_details": "Mostrar las condiciones y acciones de cada regla",
"expanded_view_description": "Mostrar reglas de filtro con bloques detallados de condiciones y acciones",
"if": "Si",
"then": "Entonces",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "Introduce una fecha de inicio o de fin para el período",
"validation_period_invalid": "Introduce una fecha válida con hora para el período o deja el campo vacío",
"apply_existing_period": "Una regla con período solo actúa sobre los mensajes que llegan dentro de él, por lo que no se puede aplicar a los mensajes existentes.",
+ "apply_existing_in": "Aplicar también a los mensajes que ya están en {folder}",
+ "apply_existing_count": "{count, plural, one {Aplicar también al # mensaje que ya está en {folder}} other {Aplicar también a los # mensajes que ya están en {folder}}}",
+ "apply_existing_none": "Ningún mensaje de {folder} coincide todavía con esta regla.",
"period_status_scheduled": "programada",
"period_status_active": "activa",
"period_status_expired": "caducada"
diff --git a/locales/et/common.json b/locales/et/common.json
index 30ac1ee96..29c3c1e9e 100644
--- a/locales/et/common.json
+++ b/locales/et/common.json
@@ -2913,6 +2913,7 @@
"open_sieve_editor": "Ava Sieve lähtekoodi redaktor",
"fetch_error": "Filtrite laadimine ebaõnnestus",
"expanded_view": "Laiendatud vaade",
+ "show_rule_details": "Näita iga reegli tingimusi ja toiminguid",
"expanded_view_description": "Näita filtrireegleid koos üksikasjalike tingimuste ja tegevuste plokkidega",
"if": "Kui",
"then": "Siis",
@@ -2991,6 +2992,9 @@
"validation_period_empty": "Sisesta ajavahemiku algus- või lõppkuupäev",
"validation_period_invalid": "Sisesta ajavahemiku jaoks kehtiv kuupäev koos kellaajaga või jäta väli tühjaks",
"apply_existing_period": "Ajavahemikuga reegel toimib ainult kirjadele, mis saabuvad selle jooksul, seega ei saa seda olemasolevatele kirjadele rakendada.",
+ "apply_existing_in": "Rakenda ka kirjadele, mis on juba kaustas {folder}",
+ "apply_existing_count": "{count, plural, one {Rakenda ka # kirjale, mis on juba kaustas {folder}} other {Rakenda ka # kirjale, mis on juba kaustas {folder}}}",
+ "apply_existing_none": "Kaustas {folder} pole veel ühtegi kirja, mis selle reegliga sobiks.",
"period_status_scheduled": "ajastatud",
"period_status_active": "aktiivne",
"period_status_expired": "aegunud"
diff --git a/locales/fa/common.json b/locales/fa/common.json
index 117abe12f..7adb7bd7c 100644
--- a/locales/fa/common.json
+++ b/locales/fa/common.json
@@ -2913,6 +2913,7 @@
"open_sieve_editor": "باز کردن ویرایشگر خام Sieve",
"fetch_error": "بارگذاری فیلترها ناموفق بود",
"expanded_view": "نمای گسترده",
+ "show_rule_details": "نمایش شرطها و کارهای هر قانون",
"expanded_view_description": "نمایش قوانین فیلتر با بلوکهای شرط و عملیات جزئی",
"if": "اگر",
"then": "آنگاه",
@@ -2991,6 +2992,9 @@
"validation_period_empty": "تاریخ شروع یا پایان بازه را وارد کنید",
"validation_period_invalid": "برای بازه یک تاریخ معتبر همراه با ساعت وارد کنید یا فیلد را خالی بگذارید",
"apply_existing_period": "قانونی که بازه زمانی دارد فقط روی پیامهایی عمل میکند که در آن بازه میرسند، بنابراین روی پیامهای موجود اجرا نمیشود.",
+ "apply_existing_in": "روی پیامهایی هم که الان در {folder} هستند اعمال شود",
+ "apply_existing_count": "{count, plural, one {روی # پیامی هم که الان در {folder} است اعمال شود} other {روی # پیامی هم که الان در {folder} هستند اعمال شود}}",
+ "apply_existing_none": "هنوز هیچ پیامی در {folder} با این قانون جور نیست.",
"period_status_scheduled": "زمانبندیشده",
"period_status_active": "فعال",
"period_status_expired": "منقضیشده"
diff --git a/locales/fr/common.json b/locales/fr/common.json
index 920bc103e..3f042bf5f 100644
--- a/locales/fr/common.json
+++ b/locales/fr/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "Ouvrir l'éditeur Sieve brut",
"fetch_error": "Échec du chargement des filtres",
"expanded_view": "Vue étendue",
+ "show_rule_details": "Afficher les conditions et actions de chaque règle",
"expanded_view_description": "Afficher les règles de filtre avec des blocs de conditions et d'actions détaillés",
"if": "Si",
"then": "Alors",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "Indiquez une date de début ou de fin pour la période",
"validation_period_invalid": "Indiquez une date valide avec l'heure pour la période, ou laissez le champ vide",
"apply_existing_period": "Une règle avec une période n'agit que sur les messages qui arrivent pendant celle-ci ; elle ne peut donc pas s'appliquer aux messages existants.",
+ "apply_existing_in": "Appliquer aussi aux messages déjà dans {folder}",
+ "apply_existing_count": "{count, plural, one {Appliquer aussi au # message déjà dans {folder}} other {Appliquer aussi aux # messages déjà dans {folder}}}",
+ "apply_existing_none": "Aucun message de {folder} ne correspond encore à cette règle.",
"period_status_scheduled": "planifiée",
"period_status_active": "active",
"period_status_expired": "expirée"
diff --git a/locales/he/common.json b/locales/he/common.json
index 2ddbebc18..fd517e8ff 100644
--- a/locales/he/common.json
+++ b/locales/he/common.json
@@ -2803,6 +2803,7 @@
"open_sieve_editor": "פתח את עורך Sieve הגולמי",
"fetch_error": "טעינת המסננים נכשלה",
"expanded_view": "תצוגה מורחבת",
+ "show_rule_details": "הצגת התנאים והפעולות של כל כלל",
"expanded_view_description": "הצג כללי סינון עם תנאים מפורטים ואבני פעולה",
"if": "אם",
"then": "ואז",
@@ -2884,6 +2885,9 @@
"validation_period_empty": "יש להזין תאריך התחלה או סיום לטווח",
"validation_period_invalid": "יש להזין תאריך תקין עם שעה לטווח, או להשאיר את השדה ריק",
"apply_existing_period": "כלל עם טווח זמן פועל רק על הודעות שמגיעות בתוכו, ולכן לא ניתן להחיל אותו על הודעות קיימות.",
+ "apply_existing_in": "להחיל גם על ההודעות שכבר נמצאות בתיקייה {folder}",
+ "apply_existing_count": "{count, plural, one {להחיל גם על ההודעה שכבר נמצאת בתיקייה {folder}} other {להחיל גם על # ההודעות שכבר נמצאות בתיקייה {folder}}}",
+ "apply_existing_none": "עדיין אין הודעה בתיקייה {folder} שמתאימה לכלל הזה.",
"period_status_scheduled": "מתוזמן",
"period_status_active": "פעיל",
"period_status_expired": "פג תוקף"
diff --git a/locales/hu/common.json b/locales/hu/common.json
index 40440385b..fbdfc8d5d 100644
--- a/locales/hu/common.json
+++ b/locales/hu/common.json
@@ -2909,6 +2909,7 @@
"open_sieve_editor": "Nyers Sieve szerkesztő megnyitása",
"fetch_error": "Nem sikerült betölteni a szűrőket",
"expanded_view": "Részletes nézet",
+ "show_rule_details": "Minden szabály feltételeinek és műveleteinek megjelenítése",
"expanded_view_description": "Szűrőszabályok megjelenítése részletes feltétel- és műveletblokkokkal",
"if": "Ha",
"then": "Akkor",
@@ -2987,6 +2988,9 @@
"validation_period_empty": "Adjon meg kezdő vagy befejező dátumot az időszakhoz",
"validation_period_invalid": "Adjon meg érvényes dátumot időponttal az időszakhoz, vagy hagyja üresen a mezőt",
"apply_existing_period": "Az időszakhoz kötött szabály csak az abban érkező üzenetekre hat, ezért meglévő üzenetekre nem alkalmazható.",
+ "apply_existing_in": "Alkalmazás a már itt lévő üzenetekre is: {folder}",
+ "apply_existing_count": "{count, plural, one {Alkalmazás a már itt lévő # üzenetre is: {folder}} other {Alkalmazás a már itt lévő # üzenetre is: {folder}}}",
+ "apply_existing_none": "Itt még egy üzenet sem felel meg ennek a szabálynak: {folder}.",
"period_status_scheduled": "ütemezett",
"period_status_active": "aktív",
"period_status_expired": "lejárt"
diff --git a/locales/it/common.json b/locales/it/common.json
index 4c928e274..4bca997d1 100644
--- a/locales/it/common.json
+++ b/locales/it/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "Apri editor Sieve",
"fetch_error": "Impossibile caricare i filtri",
"expanded_view": "Vista espansa",
+ "show_rule_details": "Mostra condizioni e azioni di ogni regola",
"expanded_view_description": "Mostra le regole dei filtri con blocchi dettagliati di condizioni e azioni",
"if": "Se",
"then": "Allora",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "Inserisci una data di inizio o di fine per il periodo",
"validation_period_invalid": "Inserisci una data valida con l'ora per il periodo oppure lascia vuoto il campo",
"apply_existing_period": "Una regola con periodo agisce solo sui messaggi che arrivano al suo interno, quindi non si può applicare ai messaggi esistenti.",
+ "apply_existing_in": "Applica anche ai messaggi già in {folder}",
+ "apply_existing_count": "{count, plural, one {Applica anche al # messaggio già in {folder}} other {Applica anche ai # messaggi già in {folder}}}",
+ "apply_existing_none": "Nessun messaggio in {folder} corrisponde ancora a questa regola.",
"period_status_scheduled": "programmata",
"period_status_active": "attiva",
"period_status_expired": "scaduta"
diff --git a/locales/ja/common.json b/locales/ja/common.json
index a4788a73e..221d08947 100644
--- a/locales/ja/common.json
+++ b/locales/ja/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "Sieveスクリプトエディタを開く",
"fetch_error": "フィルターの読み込みに失敗しました",
"expanded_view": "詳細表示",
+ "show_rule_details": "各ルールの条件と動作を表示",
"expanded_view_description": "フィルタールールを条件とアクションのブロックで表示",
"if": "条件",
"then": "実行",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "期間の開始日または終了日を入力してください",
"validation_period_invalid": "期間には時刻付きの有効な日付を入力するか、欄を空のままにしてください",
"apply_existing_period": "期間付きのルールは期間内に届いたメッセージにのみ適用されるため、既存のメッセージには適用できません。",
+ "apply_existing_in": "{folder} にあるメッセージにも適用する",
+ "apply_existing_count": "{count, plural, other {{folder} にある # 件にも適用する}}",
+ "apply_existing_none": "{folder} にこのルールに合うメッセージはまだありません。",
"period_status_scheduled": "予定",
"period_status_active": "有効",
"period_status_expired": "期限切れ"
diff --git a/locales/ko/common.json b/locales/ko/common.json
index 8692e53c6..bce249371 100644
--- a/locales/ko/common.json
+++ b/locales/ko/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "원본 Sieve 에디터 열기",
"fetch_error": "필터를 불러오지 못했어요",
"expanded_view": "자세히 보기",
+ "show_rule_details": "각 규칙의 조건과 동작 표시",
"expanded_view_description": "필터 규칙의 조건과 동작을 모두 펼쳐서 보여줘요",
"if": "만약 (If)",
"then": "다음 동작 실행 (Then)",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "기간의 시작일 또는 종료일을 입력해 주세요",
"validation_period_invalid": "기간에 시간을 포함한 올바른 날짜를 입력하거나 칸을 비워 두세요",
"apply_existing_period": "기간이 설정된 규칙은 그 기간에 도착한 메시지에만 적용되므로 기존 메시지에는 적용할 수 없어요.",
+ "apply_existing_in": "{folder}에 이미 있는 메일에도 적용",
+ "apply_existing_count": "{count, plural, other {{folder}에 이미 있는 메일 #개에도 적용}}",
+ "apply_existing_none": "{folder}에 이 규칙에 맞는 메일이 아직 없습니다.",
"period_status_scheduled": "예정",
"period_status_active": "활성",
"period_status_expired": "만료"
diff --git a/locales/lv/common.json b/locales/lv/common.json
index 30ae51e41..a068c1422 100644
--- a/locales/lv/common.json
+++ b/locales/lv/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "Atvērt Sieve redaktoru",
"fetch_error": "Neizdevās ielādēt filtrus",
"expanded_view": "Izvērstais skats",
+ "show_rule_details": "Rādīt katra noteikuma nosacījumus un darbības",
"expanded_view_description": "Rādīt filtra noteikumus ar detalizētiem nosacījumiem un darbībām",
"if": "Ja",
"then": "Tad",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "Norādiet laika posma sākuma vai beigu datumu",
"validation_period_invalid": "Norādiet laika posmam derīgu datumu ar laiku vai atstājiet lauku tukšu",
"apply_existing_period": "Noteikums ar laika posmu darbojas tikai ar ziņojumiem, kas pienāk šajā posmā, tāpēc to nevar lietot esošajiem ziņojumiem.",
+ "apply_existing_in": "Piemērot arī vēstulēm, kas jau ir mapē {folder}",
+ "apply_existing_count": "{count, plural, zero {Piemērot arī # vēstulēm, kas jau ir mapē {folder}} one {Piemērot arī # vēstulei, kas jau ir mapē {folder}} other {Piemērot arī # vēstulēm, kas jau ir mapē {folder}}}",
+ "apply_existing_none": "Mapē {folder} vēl nav nevienas vēstules, kas atbilst šim noteikumam.",
"period_status_scheduled": "ieplānots",
"period_status_active": "aktīvs",
"period_status_expired": "beidzies"
diff --git a/locales/mn/common.json b/locales/mn/common.json
index 677689faa..08f55f409 100644
--- a/locales/mn/common.json
+++ b/locales/mn/common.json
@@ -2913,6 +2913,7 @@
"open_sieve_editor": "Raw Sieve редакторыг нээнэ үү",
"fetch_error": "Шүүлтүүрийг ачаалж чадсангүй",
"expanded_view": "Өргөтгөсөн харах",
+ "show_rule_details": "Дүрэм бүрийн нөхцөл, үйлдлийг харуулах",
"expanded_view_description": "Шүүлтүүрийн дүрмийг нарийвчилсан нөхцөл, үйлдлийн блокоор харуулах",
"if": "Хэрэв",
"then": "Дараа нь",
@@ -2991,6 +2992,9 @@
"validation_period_empty": "Хугацааны эхлэх эсвэл төгсгөлийн огноог оруулна уу",
"validation_period_invalid": "Хугацаанд цагтай хүчинтэй огноо оруулах эсвэл талбарыг хоосон үлдээнэ үү",
"apply_existing_period": "Хугацаатай дүрэм зөвхөн тэр хугацаанд ирсэн мессежид үйлчилдэг тул одоо байгаа мессежид хэрэглэх боломжгүй.",
+ "apply_existing_in": "{folder} доторх байгаа захианд бас хэрэглэх",
+ "apply_existing_count": "{count, plural, one {{folder} доторх байгаа # захианд бас хэрэглэх} other {{folder} доторх байгаа # захианд бас хэрэглэх}}",
+ "apply_existing_none": "{folder} дотор энэ дүрэмд тохирох захиа одоогоор алга.",
"period_status_scheduled": "төлөвлөсөн",
"period_status_active": "идэвхтэй",
"period_status_expired": "хугацаа дууссан"
diff --git a/locales/nb/common.json b/locales/nb/common.json
index bc849a939..fad34e00d 100644
--- a/locales/nb/common.json
+++ b/locales/nb/common.json
@@ -2913,6 +2913,7 @@
"open_sieve_editor": "Åpne redigereren for Sieve-kode",
"fetch_error": "Kunne ikke laste inn filtre",
"expanded_view": "Utvidet visning",
+ "show_rule_details": "Vis betingelsene og handlingene for hver regel",
"expanded_view_description": "Vis filterregler med detaljerte blokker for vilkår og handlinger",
"if": "Hvis",
"then": "Gjør følgende",
@@ -2991,6 +2992,9 @@
"validation_period_empty": "Angi en start- eller sluttdato for perioden",
"validation_period_invalid": "Angi en gyldig dato med klokkeslett for perioden, eller la feltet stå tomt",
"apply_existing_period": "En regel med periode virker bare på meldinger som kommer i perioden, og kan derfor ikke brukes på eksisterende meldinger.",
+ "apply_existing_in": "Bruk også på meldingene som allerede er i {folder}",
+ "apply_existing_count": "{count, plural, one {Bruk også på den # meldingen som allerede er i {folder}} other {Bruk også på de # meldingene som allerede er i {folder}}}",
+ "apply_existing_none": "Ingen meldinger i {folder} passer med regelen ennå.",
"period_status_scheduled": "planlagt",
"period_status_active": "aktiv",
"period_status_expired": "utløpt"
diff --git a/locales/nl/common.json b/locales/nl/common.json
index 40c5b7aba..0c4a13c91 100644
--- a/locales/nl/common.json
+++ b/locales/nl/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "Sieve-scripteditor openen",
"fetch_error": "Filters konden niet worden geladen",
"expanded_view": "Uitgebreide weergave",
+ "show_rule_details": "Voorwaarden en acties van elke regel tonen",
"expanded_view_description": "Filterregels weergeven met gedetailleerde voorwaarde- en actieblokken",
"if": "Als",
"then": "Dan",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "Vul een start- of einddatum voor de periode in",
"validation_period_invalid": "Vul voor de periode een geldige datum met tijd in, of laat het veld leeg",
"apply_existing_period": "Een regel met een periode werkt alleen op berichten die binnen die periode binnenkomen en kan dus niet op bestaande berichten worden toegepast.",
+ "apply_existing_in": "Ook toepassen op de berichten die al in {folder} staan",
+ "apply_existing_count": "{count, plural, one {Ook toepassen op het # bericht dat al in {folder} staat} other {Ook toepassen op de # berichten die al in {folder} staan}}",
+ "apply_existing_none": "Nog geen bericht in {folder} past bij deze regel.",
"period_status_scheduled": "gepland",
"period_status_active": "actief",
"period_status_expired": "verlopen"
diff --git a/locales/pl/common.json b/locales/pl/common.json
index 977c2f348..7f0c65de7 100644
--- a/locales/pl/common.json
+++ b/locales/pl/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "Otwórz surowy edytor Sieve",
"fetch_error": "Nie udało się załadować filtrów",
"expanded_view": "Widok rozszerzony",
+ "show_rule_details": "Pokaż warunki i działania każdej reguły",
"expanded_view_description": "Pokazuj reguły filtrów ze szczegółowymi blokami warunków i akcji",
"if": "Jeśli",
"then": "Wtedy",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "Podaj datę rozpoczęcia lub zakończenia okresu",
"validation_period_invalid": "Podaj prawidłową datę z godziną dla okresu albo pozostaw pole puste",
"apply_existing_period": "Reguła z okresem działa tylko na wiadomości, które przychodzą w tym okresie, dlatego nie można jej zastosować do istniejących wiadomości.",
+ "apply_existing_in": "Zastosuj też do wiadomości, które już są w folderze {folder}",
+ "apply_existing_count": "{count, plural, one {Zastosuj też do # wiadomości, która już jest w folderze {folder}} few {Zastosuj też do # wiadomości, które już są w folderze {folder}} many {Zastosuj też do # wiadomości, które już są w folderze {folder}} other {Zastosuj też do # wiadomości, które już są w folderze {folder}}}",
+ "apply_existing_none": "Żadna wiadomość w folderze {folder} nie pasuje jeszcze do tej reguły.",
"period_status_scheduled": "zaplanowana",
"period_status_active": "aktywna",
"period_status_expired": "wygasła"
diff --git a/locales/pt/common.json b/locales/pt/common.json
index 4b3b27d99..aa6151795 100644
--- a/locales/pt/common.json
+++ b/locales/pt/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "Abrir editor Sieve",
"fetch_error": "Falha ao carregar filtros",
"expanded_view": "Vista expandida",
+ "show_rule_details": "Mostrar as condições e ações de cada regra",
"expanded_view_description": "Mostrar regras de filtro com blocos detalhados de condições e ações",
"if": "Se",
"then": "Então",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "Indique uma data de início ou de fim para o período",
"validation_period_invalid": "Indique uma data válida com hora para o período ou deixe o campo vazio",
"apply_existing_period": "Uma regra com período só atua sobre as mensagens que chegam dentro dele, por isso não pode ser aplicada às mensagens existentes.",
+ "apply_existing_in": "Aplicar também às mensagens que já estão em {folder}",
+ "apply_existing_count": "{count, plural, one {Aplicar também à # mensagem que já está em {folder}} other {Aplicar também às # mensagens que já estão em {folder}}}",
+ "apply_existing_none": "Nenhuma mensagem em {folder} corresponde ainda a esta regra.",
"period_status_scheduled": "agendada",
"period_status_active": "ativa",
"period_status_expired": "expirada"
diff --git a/locales/ro/common.json b/locales/ro/common.json
index 60c77c966..2e7d95aed 100644
--- a/locales/ro/common.json
+++ b/locales/ro/common.json
@@ -2913,6 +2913,7 @@
"open_sieve_editor": "Deschideți editorul de fișiere Sieve în format brut",
"fetch_error": "Nu s-au putut încărca filtrele",
"expanded_view": "Vizualizare extinsă",
+ "show_rule_details": "Afișați condițiile și acțiunile fiecărei reguli",
"expanded_view_description": "Afișați regulile de filtrare cu blocuri detaliate de condiții și acțiuni",
"if": "Dacă",
"then": "Apoi",
@@ -2991,6 +2992,9 @@
"validation_period_empty": "Introduceți o dată de începere sau de încheiere pentru perioadă",
"validation_period_invalid": "Introduceți o dată validă cu oră pentru perioadă sau lăsați câmpul gol",
"apply_existing_period": "O regulă cu perioadă acționează doar asupra mesajelor care sosesc în acea perioadă, deci nu poate fi aplicată mesajelor existente.",
+ "apply_existing_in": "Aplicați și mesajelor care sunt deja în {folder}",
+ "apply_existing_count": "{count, plural, one {Aplicați și # mesajului care este deja în {folder}} few {Aplicați și celor # mesaje care sunt deja în {folder}} other {Aplicați și celor # de mesaje care sunt deja în {folder}}}",
+ "apply_existing_none": "Niciun mesaj din {folder} nu se potrivește încă acestei reguli.",
"period_status_scheduled": "programată",
"period_status_active": "activă",
"period_status_expired": "expirată"
diff --git a/locales/ru/common.json b/locales/ru/common.json
index 3a0c9fcec..3d4dc098f 100644
--- a/locales/ru/common.json
+++ b/locales/ru/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "Открыть редактор Sieve",
"fetch_error": "Не удалось загрузить фильтры",
"expanded_view": "Расширенный вид",
+ "show_rule_details": "Показывать условия и действия каждого правила",
"expanded_view_description": "Показывать правила фильтрации с подробными блоками условий и действий",
"if": "Если",
"then": "То",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "Укажите дату начала или окончания периода",
"validation_period_invalid": "Укажите для периода корректную дату со временем или оставьте поле пустым",
"apply_existing_period": "Правило с периодом действует только на письма, пришедшие в этот период, поэтому его нельзя применить к уже имеющимся письмам.",
+ "apply_existing_in": "Применить и к письмам, которые уже есть в папке {folder}",
+ "apply_existing_count": "{count, plural, one {Применить и к # письму, которое уже есть в папке {folder}} few {Применить и к # письмам, которые уже есть в папке {folder}} many {Применить и к # письмам, которые уже есть в папке {folder}} other {Применить и к # письма, которые уже есть в папке {folder}}}",
+ "apply_existing_none": "В папке {folder} пока нет писем под это правило.",
"period_status_scheduled": "запланировано",
"period_status_active": "активно",
"period_status_expired": "истекло"
diff --git a/locales/sk/common.json b/locales/sk/common.json
index 502164d6d..975bfd892 100644
--- a/locales/sk/common.json
+++ b/locales/sk/common.json
@@ -2913,6 +2913,7 @@
"open_sieve_editor": "Otvoriť textový editor Sieve",
"fetch_error": "Nepodarilo sa načítať filtre",
"expanded_view": "Rozšírené zobrazenie",
+ "show_rule_details": "Zobraziť podmienky a akcie každého pravidla",
"expanded_view_description": "Zobrazovať pravidlá filtrov s podrobnými blokmi podmienok a akcií",
"if": "Ak",
"then": "Potom",
@@ -2991,6 +2992,9 @@
"validation_period_empty": "Zadajte dátum začiatku alebo ukončenia obdobia",
"validation_period_invalid": "Zadajte pre obdobie platný dátum aj s časom alebo pole nechajte prázdne",
"apply_existing_period": "Pravidlo s obdobím pôsobí len na správy, ktoré v ňom prídu, preto ho nemožno použiť na existujúce správy.",
+ "apply_existing_in": "Použiť aj na správy, ktoré už sú v priečinku {folder}",
+ "apply_existing_count": "{count, plural, one {Použiť aj na # správu, ktorá už je v priečinku {folder}} few {Použiť aj na # správy, ktoré už sú v priečinku {folder}} many {Použiť aj na # správy, ktoré už sú v priečinku {folder}} other {Použiť aj na # správ, ktoré už sú v priečinku {folder}}}",
+ "apply_existing_none": "Tomuto pravidlu zatiaľ nezodpovedá žiadna správa v priečinku {folder}.",
"period_status_scheduled": "naplánované",
"period_status_active": "aktívne",
"period_status_expired": "uplynulo"
diff --git a/locales/th/common.json b/locales/th/common.json
index 852be7f21..cf8c4dc09 100644
--- a/locales/th/common.json
+++ b/locales/th/common.json
@@ -5913,6 +5913,7 @@
"open_sieve_editor": "เปิดตัวแก้ไข Sieve โดยตรง",
"fetch_error": "โหลดตัวกรองไม่สำเร็จ",
"expanded_view": "มุมมองขยาย",
+ "show_rule_details": "แสดงเงื่อนไขและการทำงานของแต่ละกฎ",
"expanded_view_description": "แสดงกฎตัวกรองพร้อมบล็อกเงื่อนไขและการดำเนินการโดยละเอียด",
"if": "ถ้า (If)",
"then": "แล้ว (Then)",
@@ -5991,6 +5992,9 @@
"validation_period_empty": "ป้อนวันที่เริ่มต้นหรือวันที่สิ้นสุดสำหรับช่วงเวลา",
"validation_period_invalid": "ป้อนวันที่และเวลาที่ถูกต้อง หรือเว้นว่างไว้",
"apply_existing_period": "กฎที่มีการกำหนดช่วงเวลาจะมีผลกับข้อความที่มาถึงในช่วงเวลานั้นเท่านั้น จึงไม่สามารถใช้กับข้อความที่มีอยู่ได้",
+ "apply_existing_in": "ใช้กับข้อความที่อยู่ใน {folder} แล้วด้วย",
+ "apply_existing_count": "{count, plural, other {ใช้กับข้อความ # ฉบับที่อยู่ใน {folder} แล้วด้วย}}",
+ "apply_existing_none": "ยังไม่มีข้อความใน {folder} ที่ตรงกับกฎนี้",
"period_status_scheduled": "กำหนดเวลาแล้ว",
"period_status_active": "ใช้งานอยู่",
"period_status_expired": "หมดอายุแล้ว"
diff --git a/locales/tr/common.json b/locales/tr/common.json
index 8e246b38f..c720854cb 100644
--- a/locales/tr/common.json
+++ b/locales/tr/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "Ham Sieve düzenleyicisini aç",
"fetch_error": "Filtreler yüklenemedi",
"expanded_view": "Genişletilmiş görünüm",
+ "show_rule_details": "Her kuralın koşullarını ve işlemlerini göster",
"expanded_view_description": "Filtre kurallarını ayrıntılı koşul ve işlem bloklarıyla göster",
"if": "Eğer",
"then": "O zaman",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "Dönem için bir başlangıç veya bitiş tarihi girin",
"validation_period_invalid": "Dönem için saatiyle birlikte geçerli bir tarih girin veya alanı boş bırakın",
"apply_existing_period": "Dönemi olan bir kural yalnızca o dönemde gelen iletilere uygulanır, bu nedenle mevcut iletilere uygulanamaz.",
+ "apply_existing_in": "{folder} içindeki mevcut iletilere de uygula",
+ "apply_existing_count": "{count, plural, one {{folder} içindeki # mevcut iletiye de uygula} other {{folder} içindeki # mevcut iletiye de uygula}}",
+ "apply_existing_none": "{folder} içinde bu kurala uyan ileti henüz yok.",
"period_status_scheduled": "planlandı",
"period_status_active": "etkin",
"period_status_expired": "süresi doldu"
diff --git a/locales/uk/common.json b/locales/uk/common.json
index 52bf3725a..340024098 100644
--- a/locales/uk/common.json
+++ b/locales/uk/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "Відкрийте редактор Raw Sieve",
"fetch_error": "Не вдалося завантажити фільтри",
"expanded_view": "Розгорнутий вигляд",
+ "show_rule_details": "Показувати умови й дії кожного правила",
"expanded_view_description": "Показати правила фільтрації з детальними умовами та блоками дій",
"if": "Якщо",
"then": "Потім",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "Вкажіть дату початку або закінчення періоду",
"validation_period_invalid": "Вкажіть для періоду дійсну дату з часом або залиште поле порожнім",
"apply_existing_period": "Правило з періодом діє лише на листи, що надходять у цей період, тому його не можна застосувати до наявних листів.",
+ "apply_existing_in": "Застосувати й до листів, які вже є в теці {folder}",
+ "apply_existing_count": "{count, plural, one {Застосувати й до # листа, який уже є в теці {folder}} few {Застосувати й до # листів, які вже є в теці {folder}} many {Застосувати й до # листів, які вже є в теці {folder}} other {Застосувати й до # листа, які вже є в теці {folder}}}",
+ "apply_existing_none": "У теці {folder} поки немає листів під це правило.",
"period_status_scheduled": "заплановано",
"period_status_active": "активне",
"period_status_expired": "завершено"
diff --git a/locales/vi/common.json b/locales/vi/common.json
index a02cf42d1..b717d7c32 100644
--- a/locales/vi/common.json
+++ b/locales/vi/common.json
@@ -2925,6 +2925,7 @@
"open_sieve_editor": "Mở trình chỉnh sửa mã Sieve",
"fetch_error": "Không thể tải bộ lọc",
"expanded_view": "Chế độ xem mở rộng",
+ "show_rule_details": "Hiện điều kiện và hành động của từng quy tắc",
"expanded_view_description": "Hiển thị quy tắc lọc với các khối hành động và điều kiện chi tiết",
"if": "Nếu",
"then": "Sau đó",
@@ -3003,6 +3004,9 @@
"validation_period_empty": "Nhập ngày bắt đầu hoặc ngày kết thúc cho khoảng thời gian",
"validation_period_invalid": "Nhập ngày hợp lệ cùng với thời gian trong khoảng thời gian hoặc để trống trường",
"apply_existing_period": "Quy tắc có giới hạn thời gian chỉ áp dụng cho thư đến trong khoảng đó, nên không thể chạy trên các thư hiện có.",
+ "apply_existing_in": "Áp dụng cả cho các thư đã có trong {folder}",
+ "apply_existing_count": "{count, plural, other {Áp dụng cả cho # thư đã có trong {folder}}}",
+ "apply_existing_none": "Chưa có thư nào trong {folder} khớp với quy tắc này.",
"period_status_scheduled": "Theo lịch trình",
"period_status_active": "Hoạt động",
"period_status_expired": "Hết hạn"
diff --git a/locales/zh-TW/common.json b/locales/zh-TW/common.json
index afe32e3ed..31ec70b4b 100644
--- a/locales/zh-TW/common.json
+++ b/locales/zh-TW/common.json
@@ -2913,6 +2913,7 @@
"open_sieve_editor": "開啟原始 Sieve 編輯器",
"fetch_error": "無法載入篩選規則",
"expanded_view": "展開檢視",
+ "show_rule_details": "顯示每條規則的條件和動作",
"expanded_view_description": "顯示包含詳細條件與動作區塊的篩選規則",
"if": "如果",
"then": "然後",
@@ -2991,6 +2992,9 @@
"validation_period_empty": "請輸入期間的開始日期或結束日期",
"validation_period_invalid": "請為期間輸入含時間的有效日期,或將該欄位留空",
"apply_existing_period": "設定了期間的規則只作用於在該期間內收到的郵件,因此無法套用到既有郵件。",
+ "apply_existing_in": "同時套用到{folder}中既有的郵件",
+ "apply_existing_count": "{count, plural, other {同時套用到{folder}中既有的 # 封郵件}}",
+ "apply_existing_none": "{folder}中還沒有符合此規則的郵件。",
"period_status_scheduled": "尚未開始",
"period_status_active": "生效中",
"period_status_expired": "已過期"
diff --git a/locales/zh/common.json b/locales/zh/common.json
index a5fd459b2..ca69b6e4b 100644
--- a/locales/zh/common.json
+++ b/locales/zh/common.json
@@ -2906,6 +2906,7 @@
"open_sieve_editor": "打开原始 Sieve 编辑器",
"fetch_error": "加载过滤器失败",
"expanded_view": "展开视图",
+ "show_rule_details": "显示每条规则的条件和操作",
"expanded_view_description": "显示包含详细条件和操作的过滤规则",
"if": "如果",
"then": "然后",
@@ -2984,6 +2985,9 @@
"validation_period_empty": "请输入时间段的开始日期或结束日期",
"validation_period_invalid": "请为时间段输入带时间的有效日期,或将该字段留空",
"apply_existing_period": "设置了时间段的规则只作用于在该时间段内收到的邮件,因此无法应用于已有邮件。",
+ "apply_existing_in": "同时应用于{folder}中已有的邮件",
+ "apply_existing_count": "{count, plural, other {同时应用于{folder}中已有的 # 封邮件}}",
+ "apply_existing_none": "{folder}中还没有符合此规则的邮件。",
"period_status_scheduled": "未开始",
"period_status_active": "生效中",
"period_status_expired": "已过期"
From 760a400074a1a70ee5b11bcfe3a201c14f3d3729 Mon Sep 17 00:00:00 2001
From: Linus Rath <139418639+rathlinus@users.noreply.github.com>
Date: Wed, 4 Nov 2026 12:04:03 +0100
Subject: [PATCH 03/13] feat: turn out of office off from the banner in the
mail sidebar
---
.../sidebar-vacation-banner.test.tsx | 26 ++++++++-
components/layout/sidebar.tsx | 54 +++++++++++++++----
locales/ar/common.json | 1 +
locales/ca/common.json | 1 +
locales/cs/common.json | 1 +
locales/da/common.json | 1 +
locales/de/common.json | 1 +
locales/en/common.json | 1 +
locales/es/common.json | 1 +
locales/et/common.json | 1 +
locales/fa/common.json | 1 +
locales/fr/common.json | 1 +
locales/he/common.json | 1 +
locales/hu/common.json | 1 +
locales/it/common.json | 1 +
locales/ja/common.json | 1 +
locales/ko/common.json | 1 +
locales/lv/common.json | 1 +
locales/mn/common.json | 1 +
locales/nb/common.json | 1 +
locales/nl/common.json | 1 +
locales/pl/common.json | 1 +
locales/pt/common.json | 1 +
locales/ro/common.json | 1 +
locales/ru/common.json | 1 +
locales/sk/common.json | 1 +
locales/th/common.json | 1 +
locales/tr/common.json | 1 +
locales/uk/common.json | 1 +
locales/vi/common.json | 1 +
locales/zh-TW/common.json | 1 +
locales/zh/common.json | 1 +
32 files changed, 99 insertions(+), 11 deletions(-)
diff --git a/components/layout/__tests__/sidebar-vacation-banner.test.tsx b/components/layout/__tests__/sidebar-vacation-banner.test.tsx
index 1d2c8ff25..a34168eed 100644
--- a/components/layout/__tests__/sidebar-vacation-banner.test.tsx
+++ b/components/layout/__tests__/sidebar-vacation-banner.test.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { fireEvent, render, screen } from '@testing-library/react';
+import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';
// "Vacation responder is active" opens Settings > Out of Office, not
@@ -21,10 +21,13 @@ vi.mock('@/hooks/use-mailbox-drop', () => ({
}));
vi.mock('@/hooks/use-tag-drop', () => ({ useTagDrop: () => ({ dropHandlers: {}, isValidDropTarget: false }) }));
vi.mock('../account-switcher', () => ({ AccountSwitcher: () => null }));
+const toast = vi.hoisted(() => ({ error: vi.fn(), success: vi.fn(), info: vi.fn(), progress: vi.fn(), dismiss: vi.fn() }));
+vi.mock('@/stores/toast-store', () => ({ toast }));
const { Sidebar } = await import('../sidebar');
const { useVacationStore } = await import('@/stores/vacation-store');
const { buildSettingsPath } = await import('@/lib/deep-links');
+const { useAuthStore } = await import('@/stores/auth-store');
describe('vacation banner', () => {
it('opens the Out of Office settings', () => {
@@ -34,4 +37,25 @@ describe('vacation banner', () => {
expect(nav.push).toHaveBeenCalledWith(buildSettingsPath('vacation'));
expect(buildSettingsPath('vacation')).not.toBe('/settings');
});
+
+ // settings-p2-12: the banner says "Out of office is on", as the setting is
+ // called, and turns it off without a trip to Settings, like Gmail's "End now".
+ it('turns out of office off on the server', async () => {
+ const update = vi.fn(async () => true);
+ useAuthStore.setState({ client: {} as never });
+ useVacationStore.setState({ isEnabled: true, isSupported: true, updateVacationResponse: update } as never);
+ render();
+ fireEvent.click(screen.getByRole('button', { name: 'vacation_turn_off' }));
+ await waitFor(() => expect(update).toHaveBeenCalledWith(expect.anything(), { isEnabled: false }, undefined));
+ expect(toast.error).not.toHaveBeenCalled();
+ });
+
+ it('says so when turning it off fails', async () => {
+ const update = vi.fn(async () => { throw new Error('down'); });
+ useAuthStore.setState({ client: {} as never });
+ useVacationStore.setState({ isEnabled: true, isSupported: true, updateVacationResponse: update } as never);
+ render();
+ fireEvent.click(screen.getByRole('button', { name: 'vacation_turn_off' }));
+ await waitFor(() => expect(toast.error).toHaveBeenCalledWith('vacation_save_failed'));
+ });
});
diff --git a/components/layout/sidebar.tsx b/components/layout/sidebar.tsx
index aaf3672e5..3b41225c1 100644
--- a/components/layout/sidebar.tsx
+++ b/components/layout/sidebar.tsx
@@ -76,6 +76,7 @@ import { sidebarFolded, useUIStore } from "@/stores/ui-store";
import { useAuthStore } from "@/stores/auth-store";
import { unifiedLoadProgress } from "@/lib/unified-mailbox";
import { useVacationStore } from "@/stores/vacation-store";
+import { useManagedAccountStore } from "@/stores/managed-account-store";
import { useSettingsStore, getKeywordVisibility } from "@/stores/settings-store";
import { usePolicyStore } from "@/stores/policy-store";
import { useEmailStore, buildTagViewAccountClients } from "@/stores/email-store";
@@ -1070,26 +1071,59 @@ function DemoBanner({ ruled }: { ruled: boolean }) {
);
}
-function VacationBanner() {
+export function VacationBanner() {
const t = useTranslations('sidebar');
+ const tNotifications = useTranslations('notifications');
+ const tFilters = useTranslations('settings.filters');
const router = useRouter();
- const { isEnabled, isSupported } = useVacationStore(useShallow((state) => ({ isEnabled: state.isEnabled, isSupported: state.isSupported })));
+ const { isEnabled, isSupported, isSaving } = useVacationStore(useShallow((state) => ({
+ isEnabled: state.isEnabled, isSupported: state.isSupported, isSaving: state.isSaving,
+ })));
+ // The store holds the reply of the account Settings last loaded it for.
+ const managedAccountId = useManagedAccountStore((s) => s.managedAccountId);
+ const client = useAuthStore((s) => s.client);
+ const [turningOff, setTurningOff] = useState(false);
if (!isSupported || !isEnabled) return null;
+ // Like Gmail's "End now": off on the server, without opening Settings.
+ const turnOff = async () => {
+ if (!client || turningOff) return;
+ setTurningOff(true);
+ try {
+ await useVacationStore.getState().updateVacationResponse(client, { isEnabled: false }, managedAccountId ?? undefined);
+ } catch {
+ toast.error(tNotifications('vacation_save_failed'));
+ } finally {
+ setTurningOff(false);
+ }
+ };
+
return (
- router.push(buildSettingsPath('vacation'))}
+
+ >}
diff --git a/components/settings/__tests__/vacation-forward.test.tsx b/components/settings/__tests__/vacation-forward.test.tsx
index bf2620166..8ca2b5167 100644
--- a/components/settings/__tests__/vacation-forward.test.tsx
+++ b/components/settings/__tests__/vacation-forward.test.tsx
@@ -378,6 +378,9 @@ describe('the vacation period in the card', () => {
it('checks the fields again on save, which a field filled in only half may never have told', async () => {
const server = stalwart([rule('a')]);
await openCard(server);
+ // Typing in it: an empty field left alone turns into a text field with a
+ // placeholder (settings-p2-19).
+ fireEvent.focus(dateField(1));
fireEvent.change(dateField(1), { target: { value: '' } });
halfFilledIn(dateField(1), true);
expect(await screen.findByText('warnings.invalid_date', undefined, { timeout: 3000 })).toBeInTheDocument();
diff --git a/components/settings/__tests__/vacation-message.test.tsx b/components/settings/__tests__/vacation-message.test.tsx
index 09acc342a..1ef021a01 100644
--- a/components/settings/__tests__/vacation-message.test.tsx
+++ b/components/settings/__tests__/vacation-message.test.tsx
@@ -18,8 +18,8 @@ vi.mock('next-intl', () => {
});
// The editor hands the card its HTML as typed.
vi.mock('@/components/email/rich-text-editor', () => ({
- RichTextEditor: ({ content, onChange, placeholder }: { content: string; onChange: (html: string) => void; placeholder?: string }) => (
-