This commit is contained in:
Lucas Gaitzsch
2026-05-09 00:31:34 +02:00
parent f45b67fe19
commit 4a3c775b40
9 changed files with 164 additions and 95 deletions
+3 -2
View File
@@ -152,6 +152,7 @@ export function EmailContextMenu({
const showBatchActions = isMultiSelect && selectedCount > 1;
const isInJunkFolder = currentMailboxRole === 'junk';
const isScheduled = email.isScheduled === true;
const canCancelScheduled = isScheduled && email.scheduledUndoStatus === 'pending';
// Build color options from keyword definitions in settings
const colorOptions = emailKeywords.map((kw) => ({
@@ -205,7 +206,7 @@ export function EmailContextMenu({
</ContextMenuHeader>
)}
{isScheduled && !showBatchActions && (
{isScheduled && !showBatchActions && canCancelScheduled && (
<>
<ContextMenuItem
icon={CalendarClock}
@@ -228,7 +229,7 @@ export function EmailContextMenu({
</>
)}
{isScheduled && <ContextMenuSeparator />}
{canCancelScheduled && <ContextMenuSeparator />}
{!isScheduled && (
<>
+29 -20
View File
@@ -505,30 +505,39 @@ export function EmailList({
/>
{isScheduledView && thread.latestEmail.isScheduled && (
<div className="flex flex-wrap items-center gap-2 border-b border-border bg-muted/10 px-4 py-2 text-xs">
{thread.latestEmail.scheduledUndoStatus && thread.latestEmail.scheduledUndoStatus !== 'pending' && (
<span className="rounded-full bg-muted px-2 py-0.5 text-muted-foreground">
{thread.latestEmail.scheduledUndoStatus}
</span>
)}
<span className="flex items-center gap-1 text-muted-foreground">
<CalendarClock className="w-3.5 h-3.5" />
{new Date(thread.latestEmail.scheduledSendAt || '').toLocaleString()}
</span>
<Button variant="ghost" size="sm" className="h-7 px-2" onClick={() => onCancelScheduled?.(thread.latestEmail)}>
<XCircle className="w-3.5 h-3.5 mr-1" />
{t('cancel_scheduled_send')}
</Button>
<Button
variant="ghost"
size="sm"
className="h-7 px-2"
onClick={() => {
const delayedUntil = promptForRescheduleDelayedUntil();
if (delayedUntil) onRescheduleScheduled?.(thread.latestEmail, delayedUntil);
}}
>
<CalendarClock className="w-3.5 h-3.5 mr-1" />
{t('reschedule_send')}
</Button>
<Button variant="ghost" size="sm" className="h-7 px-2" onClick={() => onCancelScheduledForEdit?.(thread.latestEmail)}>
<Edit3 className="w-3.5 h-3.5 mr-1" />
{thread.latestEmail.isSmimeScheduled ? t('cancel_and_compose_again') : t('cancel_and_edit')}
</Button>
{thread.latestEmail.scheduledUndoStatus === 'pending' && (
<>
<Button variant="ghost" size="sm" className="h-7 px-2" onClick={() => onCancelScheduled?.(thread.latestEmail)}>
<XCircle className="w-3.5 h-3.5 mr-1" />
{t('cancel_scheduled_send')}
</Button>
<Button
variant="ghost"
size="sm"
className="h-7 px-2"
onClick={() => {
const delayedUntil = promptForRescheduleDelayedUntil();
if (delayedUntil) onRescheduleScheduled?.(thread.latestEmail, delayedUntil);
}}
>
<CalendarClock className="w-3.5 h-3.5 mr-1" />
{t('reschedule_send')}
</Button>
<Button variant="ghost" size="sm" className="h-7 px-2" onClick={() => onCancelScheduledForEdit?.(thread.latestEmail)}>
<Edit3 className="w-3.5 h-3.5 mr-1" />
{thread.latestEmail.isSmimeScheduled ? t('cancel_and_compose_again') : t('cancel_and_edit')}
</Button>
</>
)}
</div>
)}
</div>
+20 -15
View File
@@ -871,6 +871,7 @@ export function EmailViewer({
// Detect if the email is a draft
const isDraft = email?.keywords?.['$draft'] === true;
const isScheduled = email?.isScheduled === true;
const canCancelScheduled = isScheduled && email?.scheduledUndoStatus === 'pending';
// Color options for email tags (from user-defined keyword settings)
const colorOptions = emailKeywords.map((kw) => ({
@@ -3137,7 +3138,7 @@ export function EmailViewer({
<ChevronLeft className="w-5 h-5" />
</Button>
)}
{isScheduled && (
{isScheduled && canCancelScheduled && (
<>
<Button variant="default" size="sm" onClick={onCancelScheduled} className="sm:flex sm:h-8" title={t('cancel_scheduled_send')}>
<X className="w-4 h-4" />
@@ -4593,20 +4594,24 @@ export function EmailViewer({
</span>
</div>
<div className="flex items-center gap-2">
<Button size="sm" variant="outline" onClick={onCancelScheduled}>{t('cancel_scheduled_send')}</Button>
<Button
size="sm"
variant="outline"
onClick={() => {
const delayedUntil = promptForRescheduleDelayedUntil();
if (delayedUntil) onRescheduleScheduled?.(delayedUntil);
}}
>
{t('reschedule_send')}
</Button>
<Button size="sm" variant="outline" onClick={onCancelScheduledForEdit}>
{email.isSmimeScheduled ? t('cancel_and_compose_again') : t('cancel_and_edit')}
</Button>
{canCancelScheduled && (
<>
<Button size="sm" variant="outline" onClick={onCancelScheduled}>{t('cancel_scheduled_send')}</Button>
<Button
size="sm"
variant="outline"
onClick={() => {
const delayedUntil = promptForRescheduleDelayedUntil();
if (delayedUntil) onRescheduleScheduled?.(delayedUntil);
}}
>
{t('reschedule_send')}
</Button>
<Button size="sm" variant="outline" onClick={onCancelScheduledForEdit}>
{email.isSmimeScheduled ? t('cancel_and_compose_again') : t('cancel_and_edit')}
</Button>
</>
)}
</div>
</div>
</div>