'use client'; import { Badge, Box, Button, Flex, Grid, Stack, Text } from '@chakra-ui/react'; import { FiFolder, FiPause, FiPlay, FiSquare, FiTrash2, FiX, } from 'react-icons/fi'; import type { BacktestJobRecord, BacktestJobStatus, } from '#app/lib/backtestJobContracts'; import type { JobAction } from './useBacktestRunsController'; const formatNumber = (value: number | null | undefined, fractionDigits = 1) => typeof value === 'number' && Number.isFinite(value) ? value.toFixed(fractionDigits) : '-'; const formatDateTime = (value: string | undefined) => { if (!value) { return '-'; } const timestamp = Date.parse(value); if (!Number.isFinite(timestamp)) { return '-'; } return new Intl.DateTimeFormat('en', { month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit', }).format(timestamp); }; const statusTone = (status: BacktestJobStatus) => { if (status === 'running') { return 'teal'; } if (status === 'pausing' || status === 'paused') { return 'yellow'; } if (status === 'completed') { return 'green'; } if (status === 'cancelled') { return 'gray'; } return 'red'; }; const statusLabel = (status: BacktestJobStatus) => status.charAt(0).toUpperCase() + status.slice(1); const getJobTitle = (job: BacktestJobRecord) => `${job.request.strategyName} / ${job.request.configId}`; interface BacktestJobItemProps { job: BacktestJobRecord; busyAction: string; onAction: (jobId: string, action: JobAction) => void; onDelete: (jobId: string) => void; onOpenResults: () => void; } export const BacktestJobItem = ({ job, busyAction, onAction, onDelete, onOpenResults, }: BacktestJobItemProps) => { const progress = job.progress; const totalLabel = progress.total == null ? '?' : progress.total; const logs = job.logs.slice(-10); const canPause = job.status === 'running'; const canResume = job.status === 'paused'; const canCancel = !['completed', 'cancelled'].includes(job.status); const canDelete = ['completed', 'cancelled', 'failed', 'paused'].includes( job.status, ); return ( {getJobTitle(job)} {statusLabel(job.status)} {job.request.ai ? AI : null} {job.request.fast ? Fast : null} Started {formatDateTime(job.startedAt)} · Updated{' '} {formatDateTime(job.updatedAt)} · Run #{job.runCount} {job.pauseReason ? ( Pause reason: {job.pauseReason} ) : null} {job.error ? ( {job.error} ) : null} {canPause ? ( <> ) : null} {canResume ? ( ) : null} {job.status === 'completed' ? ( ) : null} {canCancel ? ( ) : null} {progress.completed}/{totalLabel} tests {formatNumber(progress.percent, 1)}% {logs.length ? ( {logs.map((line, index) => ( {line} ))} ) : null} ); }; const Metric = ({ label, value }: { label: string; value: string }) => ( {label} {value} );