'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}
);