/* Copyright (C) 2023-2026 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import type { ColumnDef } from '@tanstack/react-table' /* eslint-disable react-refresh/only-export-components */ import { useState } from 'react' import { useTranslation } from 'react-i18next' import { CopyableStatusBadge, StatusBadge } from '@/components/status-badge' import { Avatar, AvatarFallback } from '@/components/ui/avatar' import { getUserAvatarFallback, getUserAvatarStyle } from '@/lib/avatar' import { formatTimestampToDate } from '@/lib/format' import { cn } from '@/lib/utils' import { getTaskPlatformName, taskActionMapper, taskStatusMapper, } from '../../lib/mappers' import type { TaskLog } from '../../types' import { TaskDetailsDialog } from '../dialogs/task-details-dialog' import { useUsageLogsContext } from '../usage-logs-provider' import { createDurationColumn, createChannelColumn, createProgressColumn, } from './column-helpers' export function useTaskLogsColumns(isAdmin: boolean): ColumnDef[] { const { t } = useTranslation() const columns: ColumnDef[] = [ { accessorKey: 'submit_time', header: t('Submit Time'), 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')} ) : ( - )}
) }, size: 180, meta: { cardRole: 'primary', cardOrder: 10, contentMode: 'full', }, }, ] if (isAdmin) { columns.push(createChannelColumn({ headerLabel: t('Channel') }), { id: 'user', header: t('User'), accessorFn: (row) => row.username || row.user_id, cell: function UserCell({ row }) { const { sensitiveVisible, setSelectedUserId, setUserInfoDialogOpen } = useUsageLogsContext() const log = row.original const displayName = log.username || String(log.user_id || '?') return ( ) }, meta: { cardRole: 'primary', cardOrder: 30, contentMode: 'wrap', }, }) } columns.push( { accessorKey: 'task_id', header: t('Task ID'), cell: ({ row }) => { const log = row.original const taskId = row.getValue('task_id') as string if (!taskId) { return - } return (
{taskId} {getTaskPlatformName(log.platform)} ·{' '} {t(taskActionMapper.getLabel(log.action))}
) }, meta: { cardRole: 'title', cardSpan: 2, contentMode: 'full', }, }, createDurationColumn({ submitTimeKey: 'submit_time', finishTimeKey: 'finish_time', unit: 'seconds', headerLabel: t('Duration'), warningThresholdSec: 300, }), { accessorKey: 'status', header: t('Status'), cell: ({ row }) => { const status = row.getValue('status') as string return ( {t(taskStatusMapper.getLabel(status, status || 'Submitting'))} ) }, meta: { cardRole: 'badge', contentMode: 'full', }, }, createProgressColumn({ headerLabel: t('Progress') }), { id: 'details', header: t('Details'), enableSorting: false, cell: function DetailsCell({ row }) { return }, size: 120, maxSize: 140, meta: { cardRole: 'secondary', cardOrder: 20, cardSpan: 2, contentMode: 'summary', }, } ) return columns } function TaskDetailsCell({ log, isAdmin }: { log: TaskLog; isAdmin: boolean }) { const { t } = useTranslation() const [open, setOpen] = useState(false) const isFailed = !!log.fail_reason && log.fail_reason.trim() !== '' return ( <> ) }