feat: add manual download and cancel download for email accounts

This commit is contained in:
rustmailer
2026-05-08 01:00:46 +08:00
parent 7eacfbfb20
commit 174d56e7b4
30 changed files with 404 additions and 49 deletions
@@ -19,7 +19,7 @@
import { DotsHorizontalIcon } from '@radix-ui/react-icons'
import { Row } from '@tanstack/react-table'
import { IconEdit, IconShieldLock, IconTrash } from '@tabler/icons-react'
import { IconEdit, IconPlayerPlay, IconPlayerStop, IconShieldLock, IconTrash } from '@tabler/icons-react'
import { Button } from '@/components/ui/button'
import {
DropdownMenu,
@@ -33,7 +33,8 @@ import { useAccountContext } from '../context'
import { Mailbox, MessageSquareMore } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { useCurrentUser } from '@/hooks/use-current-user'
import { AccountModel } from '@/api/account/api'
import { AccountModel, cancel_account_download, start_account_download } from '@/api/account/api'
import { toast } from '@/hooks/use-toast'
interface DataTableRowActionsProps {
row: Row<AccountModel>
@@ -55,6 +56,35 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) {
(account_type === 'IMAP' && hasPermission) ||
(account_type === 'IMAP' && hasReadPermission);
const showDownload = account_type === 'IMAP' && hasPermission;
const handleStartDownload = async () => {
try {
await start_account_download(row.original.id);
toast({ title: t('accounts.downloadStarted') });
} catch (error: any) {
toast({
variant: "destructive",
title: t('accounts.downloadFailed'),
description: error.response?.data?.message || error.message
});
}
}
const handleCancelDownload = async () => {
try {
await cancel_account_download(row.original.id);
toast({ title: t('accounts.downloadCancelled') });
} catch (error: any) {
toast({
variant: "destructive",
title: t('accounts.cancelFailed'),
description: error.response?.data?.message || error.message
});
}
}
return (
<>
<DropdownMenu modal={false}>
@@ -68,6 +98,26 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) {
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align='end' className='w-[220px]'>
{showDownload && (
<DropdownMenuItem onClick={handleStartDownload}>
{t('accounts.startDownload')}
<DropdownMenuShortcut>
<IconPlayerPlay size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
)}
{showDownload && (
<DropdownMenuItem onClick={handleCancelDownload}>
{t('accounts.cancelDownload')}
<DropdownMenuShortcut>
<IconPlayerStop size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
)}
{showDownload && <DropdownMenuSeparator />}
{hasPermission && <DropdownMenuItem
onClick={() => {
setCurrentRow(row.original)
@@ -298,7 +298,7 @@ export function RunningStateDialog({ currentRow, open, onOpenChange }: Props) {
{format(new Date(h.start_time), 'yyyy-MM-dd HH:mm:ss')}
</div>
<StatusBadge status={h.status} />
<div className="hidden xs:block"><TriggerBadge trigger={h.trigger} /></div>
<div className="xs:block"><TriggerBadge trigger={h.trigger} /></div>
</div>
<span className="text-[10px] font-bold text-muted-foreground bg-muted px-2 py-0.5 rounded-full self-start sm:self-auto">
{Object.keys(h.folder_details).length} {t('accounts.runningState.folders')}