feat(scheduled): Send now button on scheduled/delayed messages

Adds a 'Send now' action to the scheduled-send view (both the toolbar and the
inline banner) so a queued message — whether explicitly scheduled or held by the
undo-send delay — can be sent immediately instead of only cancel/reschedule/edit.
Reuses the existing reschedule path (reschedules the submission to now), so no
new JMAP plumbing. Toolbar 'Cancel send' demoted to ghost so 'Send now' is the
single primary action. i18n added across locales.
This commit is contained in:
Shuki Vaknin
2026-06-24 16:46:18 +02:00
committed by Linus Rath
parent f1b9f4ba50
commit baf094d026
20 changed files with 50 additions and 20 deletions
+12 -1
View File
@@ -3515,7 +3515,17 @@ export function EmailViewer({
)}
{isScheduled && canCancelScheduled && (
<>
<Button variant="default" size="sm" onClick={onCancelScheduled} className="sm:flex sm:h-8" title={t('cancel_scheduled_send')}>
<Button
variant="default"
size="sm"
onClick={() => onRescheduleScheduled?.(new Date(Date.now() + 1000).toISOString())}
className="sm:flex sm:h-8"
title={t('send_now')}
>
<Send className="w-4 h-4" />
{showToolbarLabels && <span className="hidden sm:inline text-sm">{t('send_now')}</span>}
</Button>
<Button variant="ghost" size="sm" onClick={onCancelScheduled} className="sm:flex sm:h-8" title={t('cancel_scheduled_send')}>
<X className="w-4 h-4" />
<span className="hidden sm:inline text-sm">{t('cancel_scheduled_send')}</span>
</Button>
@@ -5029,6 +5039,7 @@ export function EmailViewer({
<div className="flex items-center gap-2">
{canCancelScheduled && (
<>
<Button size="sm" variant="default" onClick={() => onRescheduleScheduled?.(new Date(Date.now() + 1000).toISOString())}>{t('send_now')}</Button>
<Button size="sm" variant="outline" onClick={onCancelScheduled}>{t('cancel_scheduled_send')}</Button>
<Button
size="sm"
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Přidat do kontaktů",
"copied": "Zkopírováno!",
"copy_failed": "Kopírování se nezdařilo"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Vyžádáno potvrzení o přečtení (kliknutím vypnete)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Tilføj til kontakter",
"copied": "Kopieret!",
"copy_failed": "Kunne ikke kopiere"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Læsekvittering anmodet (klik for at deaktivere)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Zu Kontakten hinzufügen",
"copied": "Kopiert!",
"copy_failed": "Kopieren fehlgeschlagen"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Lesebestätigung angefordert (klicken zum Deaktivieren)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Add to contacts",
"copied": "Copied!",
"copy_failed": "Failed to copy"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Read receipt requested (click to disable)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Añadir a contactos",
"copied": "¡Copiado!",
"copy_failed": "Error al copiar"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Confirmación de lectura solicitada (haz clic para desactivar)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Ajouter aux contacts",
"copied": "Copié !",
"copy_failed": "Échec de la copie"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Accusé de lecture demandé (cliquez pour désactiver)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Hozzáadás a névjegyekhez",
"copied": "Másolva!",
"copy_failed": "A másolás nem sikerült"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Olvasási visszaigazolás kérve (kattints a letiltáshoz)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Aggiungi ai contatti",
"copied": "Copiato!",
"copy_failed": "Copia non riuscita"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Conferma di lettura richiesta (clicca per disattivare)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "連絡先に追加",
"copied": "コピーしました!",
"copy_failed": "コピーに失敗しました"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "開封確認を要求中(クリックで無効化)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "연락처에 추가",
"copied": "복사됨!",
"copy_failed": "복사하지 못했습니다"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "읽음 확인 요청됨 (클릭하여 해제)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Pievienot kontaktpersonām",
"copied": "Nokopēts!",
"copy_failed": "Neizdevās nokopēt"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Pieprasīts lasīšanas apstiprinājums (noklikšķiniet, lai atspējotu)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Aan contacten toevoegen",
"copied": "Gekopieerd!",
"copy_failed": "Kopiëren mislukt"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Leesbevestiging aangevraagd (klik om uit te schakelen)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Dodaj do kontaktów",
"copied": "Skopiowano!",
"copy_failed": "Nie udało się skopiować"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Zażądano potwierdzenia przeczytania (kliknij, aby wyłączyć)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Adicionar aos contatos",
"copied": "Copiado!",
"copy_failed": "Falha ao copiar"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Confirmação de leitura solicitada (clique para desativar)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Adaugă la contacte",
"copied": "Copiat!",
"copy_failed": "Copierea a eșuat"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Solicitare confirmare de citire (faceți clic pentru a dezactiva)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Добавить в контакты",
"copied": "Скопировано!",
"copy_failed": "Не удалось скопировать"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Запрошено уведомление о прочтении (нажмите, чтобы отключить)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Kişilere ekle",
"copied": "Kopyalandı!",
"copy_failed": "Kopyalanamadı"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Okundu bilgisi istendi (devre dışı bırakmak için tıklayın)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "Додати до контактів",
"copied": "Скопійовано!",
"copy_failed": "Не вдалося скопіювати"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "Запитано сповіщення про прочитання (натисніть, щоб вимкнути)",
+2 -1
View File
@@ -565,7 +565,8 @@
"add_to_contacts": "添加到联系人",
"copied": "已复制!",
"copy_failed": "复制失败"
}
},
"send_now": "Send now"
},
"email_composer": {
"read_receipt_on": "已请求已读回执(点击以关闭)",