/* eslint-disable react-refresh/only-export-components */ import { useState, useMemo } from 'react' import type { ColumnDef } from '@tanstack/react-table' import { Music } from 'lucide-react' import { useTranslation } from 'react-i18next' import { formatTimestampToDate } from '@/lib/format' import { cn } from '@/lib/utils' import { DataTableColumnHeader } from '@/components/data-table' import { StatusBadge } from '@/components/status-badge' import { Avatar, AvatarFallback } from '@/components/ui/avatar' import { TASK_ACTIONS, TASK_STATUS } from '../../constants' import { taskActionMapper, taskStatusMapper, } from '../../lib/mappers' import type { TaskLog } from '../../types' import { getLogAvatarStyle } from '../../lib/avatar-color' import { useUsageLogsContext } from '../usage-logs-provider' import { AudioPreviewDialog, type AudioClip, } from '../dialogs/audio-preview-dialog' import { FailReasonDialog } from '../dialogs/fail-reason-dialog' import { createDurationColumn, createChannelColumn, createProgressColumn, } from './column-helpers' function parseTaskData(data: unknown): unknown[] { if (Array.isArray(data)) return data if (typeof data === 'string') { try { const parsed = JSON.parse(data) return Array.isArray(parsed) ? parsed : [] } catch { return [] } } return [] } function AudioPreviewCell({ log }: { log: TaskLog }) { const { t } = useTranslation() const [open, setOpen] = useState(false) const clips = useMemo(() => { const data = parseTaskData(log.data) return data.filter( (c) => c && typeof c === 'object' && (c as Record).audio_url ) }, [log.data]) if (clips.length === 0) return null return ( <> ) } export function useTaskLogsColumns(isAdmin: boolean): ColumnDef[] { const { t } = useTranslation() const columns: ColumnDef[] = [ { accessorKey: 'submit_time', header: ({ column }) => ( ), cell: ({ row }) => { const log = row.original const submitTime = row.getValue('submit_time') as number return (
{formatTimestampToDate(submitTime, 'seconds')} {log.finish_time ? ( {formatTimestampToDate(log.finish_time, 'seconds')} ) : ( - )}
) }, meta: { label: t('Submit Time') }, }, ] if (isAdmin) { columns.push( createChannelColumn({ headerLabel: t('Channel') }), { id: 'user', header: ({ column }) => ( ), cell: function UserCell({ row }) { const { sensitiveVisible, setSelectedUserId, setUserInfoDialogOpen, } = useUsageLogsContext() const log = row.original const displayName = log.username || String(log.user_id || '?') return ( ) }, meta: { label: t('User'), mobileHidden: true }, } ) } columns.push( { accessorKey: 'task_id', header: ({ column }) => ( ), cell: ({ row }) => { const log = row.original const taskId = row.getValue('task_id') as string if (!taskId) { return - } return (
{t(log.platform)} · {t(taskActionMapper.getLabel(log.action))}
) }, meta: { label: t('Task ID'), mobileTitle: true }, }, createDurationColumn({ submitTimeKey: 'submit_time', finishTimeKey: 'finish_time', unit: 'seconds', headerLabel: t('Duration'), warningThresholdSec: 300, }), { accessorKey: 'status', header: ({ column }) => ( ), cell: ({ row }) => { const status = row.getValue('status') as string return ( ) }, meta: { label: t('Status') }, }, createProgressColumn({ headerLabel: t('Progress') }), { accessorKey: 'fail_reason', header: ({ column }) => ( ), cell: function DetailsCell({ row }) { const log = row.original const failReason = row.getValue('fail_reason') as string const status = log.status const [dialogOpen, setDialogOpen] = useState(false) const isSunoSuccess = log.platform === 'suno' && status === TASK_STATUS.SUCCESS if (isSunoSuccess) { const data = parseTaskData(log.data) if ( data.some( (c) => c && typeof c === 'object' && (c as Record).audio_url ) ) { return } } const isVideoTask = log.action === TASK_ACTIONS.GENERATE || log.action === TASK_ACTIONS.TEXT_GENERATE || log.action === TASK_ACTIONS.FIRST_TAIL_GENERATE || log.action === TASK_ACTIONS.REFERENCE_GENERATE || log.action === TASK_ACTIONS.REMIX_GENERATE const isSuccess = status === TASK_STATUS.SUCCESS const isUrl = failReason?.startsWith('http') if (isSuccess && isVideoTask && isUrl) { const videoUrl = `/v1/videos/${log.task_id}/content` return ( {t('Click to preview video')} ) } if (!failReason) { return - } return ( <> ) }, meta: { label: t('Details') }, size: 200, maxSize: 220, } ) return columns }