diff --git a/src/routes/_authenticated/downloads/index.tsx b/src/routes/_authenticated/downloads/index.tsx index a265ec13..14c1a537 100644 --- a/src/routes/_authenticated/downloads/index.tsx +++ b/src/routes/_authenticated/downloads/index.tsx @@ -1447,6 +1447,8 @@ function OverviewPanel({ task }: { task: DownloadTask }) { return (
+ +
} @@ -1530,16 +1532,27 @@ function OverviewPanel({ task }: { task: DownloadTask }) {
+
+ ) +} - {(task.status.error?.message || detail?.message) && ( -
- -
- {task.status.error?.message &&
{task.status.error?.message}
} - {detail?.message &&
{detail.message}
} -
+function TaskErrorNotice({ task }: { task: DownloadTask }) { + const { t } = useTranslation() + const detail = task.status.runtime + const messages = [task.status.error?.message, detail?.message].filter(Boolean) as string[] + if (messages.length === 0) return null + + return ( +
+ +
+
{t('downloads.detail.errorMessage')}
+
+ {messages.map((message) => ( +
{message}
+ ))}
- )} +
) } @@ -1615,8 +1628,8 @@ function PeersPanel({ task }: { task: DownloadTask }) { maxWidth: 430, render: (peer) => (
- {peer.address} +
), }, @@ -1754,7 +1767,7 @@ function ResizableDetailTable({ } return ( - +
{columns.map((column) => ( @@ -1802,11 +1815,11 @@ function PeerRegionMark({ countryCode, regionCode }: { countryCode?: string; reg return ( - {flag && {flag}} - {label} + {flag && {flag}} + {label} ) } @@ -1834,27 +1847,80 @@ function countryCodeToFlag(countryCode: string) { function LogPanel({ task }: { task: DownloadTask }) { const { t } = useTranslation() const detail = task.status.runtime - const messages = [ - detail?.message && { label: t('downloads.detail.statusMessage'), value: detail.message }, - task.status.error?.message && { label: t('downloads.detail.errorMessage'), value: task.status.error?.message }, - { label: t('downloads.detail.createdAt'), value: formatDate(task.createdAt) }, - { label: t('downloads.detail.startedAt'), value: formatDate(task.status.startedAt) }, - { label: t('downloads.detail.finishedAt'), value: formatDate(task.status.finishedAt) }, - ].filter(Boolean) as Array<{ label: string; value: string }> + const events = [ + { + id: 'created', + tone: 'neutral', + time: formatDate(task.createdAt), + title: t('downloads.detail.createdAt'), + detail: sourceUri(task), + }, + task.status.startedAt && { + id: 'started', + tone: 'active', + time: formatDate(task.status.startedAt), + title: t('downloads.detail.startedAt'), + detail: [detail?.engine, formatPhase(detail?.phase, t)].filter(Boolean).join(' ยท '), + }, + detail?.message && { + id: 'runtime-message', + tone: 'warning', + time: formatDate(detail.updatedAt), + title: t('downloads.detail.statusMessage'), + detail: detail.message, + }, + task.status.error?.message && { + id: 'error', + tone: 'error', + time: formatDate(task.status.updatedAt), + title: t('downloads.detail.errorMessage'), + detail: task.status.error.message, + }, + task.status.finishedAt && { + id: 'finished', + tone: task.status.state === 'completed' ? 'success' : 'neutral', + time: formatDate(task.status.finishedAt), + title: t('downloads.detail.finishedAt'), + detail: t(`downloads.status.${task.status.state}`), + }, + ].filter(Boolean) as Array<{ + id: string + tone: 'active' | 'error' | 'neutral' | 'success' | 'warning' + time: string + title: string + detail: string + }> return ( -
- {messages.map((message) => ( -
-
{message.label}
-
{message.value || '-'}
+
+ {events.map((event, index) => ( +
+
+ + {index < events.length - 1 && } +
+
+
+ {event.title} + {event.time} +
+ {event.detail &&
{event.detail}
} +
))} - {messages.length === 0 && } + {events.length === 0 && }
) } +function logEventDotClass(tone: 'active' | 'error' | 'neutral' | 'success' | 'warning') { + if (tone === 'active') return 'bg-sky-500' + if (tone === 'error') return 'bg-destructive' + if (tone === 'success') return 'bg-emerald-500' + if (tone === 'warning') return 'bg-amber-500' + return 'bg-muted-foreground/50' +} + function SourceIcon({ type }: { type: DownloadTask['spec']['source']['type'] }) { if (type === 'magnet') return if (type === 'torrent_url') return