adding backtest table / pages

This commit is contained in:
Boki 2025-07-04 14:27:34 -04:00
parent 38a6e73ad5
commit a876f3c35b
19 changed files with 1058 additions and 69 deletions

View file

@ -1,14 +1,56 @@
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import { useBacktestList } from './hooks/useBacktest';
import { Link } from 'react-router-dom';
import { Link, useNavigate } from 'react-router-dom';
import {
PlusIcon,
PlayIcon,
CheckCircleIcon,
XCircleIcon,
ClockIcon,
ExclamationTriangleIcon
} from '@heroicons/react/24/solid';
export function BacktestListPage() {
const { backtests, isLoading, error, loadBacktests } = useBacktestList();
const navigate = useNavigate();
const [refreshInterval, setRefreshInterval] = useState<NodeJS.Timeout | null>(null);
useEffect(() => {
loadBacktests();
// Refresh every 5 seconds if there are running backtests
const interval = setInterval(() => {
if (backtests.some(b => b.status === 'running' || b.status === 'pending')) {
loadBacktests();
}
}, 5000);
setRefreshInterval(interval);
return () => {
if (refreshInterval) {
clearInterval(refreshInterval);
}
};
}, [loadBacktests]);
const getStatusIcon = (status: string) => {
switch (status) {
case 'completed':
return <CheckCircleIcon className="w-4 h-4 text-success" />;
case 'running':
return <PlayIcon className="w-4 h-4 text-primary-400 animate-pulse" />;
case 'pending':
return <ClockIcon className="w-4 h-4 text-text-secondary" />;
case 'failed':
return <XCircleIcon className="w-4 h-4 text-error" />;
case 'cancelled':
return <ExclamationTriangleIcon className="w-4 h-4 text-text-muted" />;
default:
return <ClockIcon className="w-4 h-4 text-text-secondary" />;
}
};
const getStatusColor = (status: string) => {
switch (status) {
case 'completed':
@ -37,12 +79,13 @@ export function BacktestListPage() {
View and manage your backtest runs
</p>
</div>
<Link
to="/backtests/new"
className="px-4 py-2 bg-primary-500 text-white rounded-md text-sm font-medium hover:bg-primary-600 transition-colors"
<button
onClick={() => navigate('/backtests/new')}
className="px-4 py-2 bg-primary-500 text-white rounded-md text-sm font-medium hover:bg-primary-600 transition-colors flex items-center space-x-2"
>
New Backtest
</Link>
<PlusIcon className="w-4 h-4" />
<span>New Backtest</span>
</button>
</div>
{error && (
@ -58,12 +101,13 @@ export function BacktestListPage() {
) : backtests.length === 0 ? (
<div className="bg-surface-secondary p-8 rounded-lg border border-border text-center">
<p className="text-text-secondary mb-4">No backtests found</p>
<Link
to="/backtests/new"
className="inline-flex px-4 py-2 bg-primary-500 text-white rounded-md text-sm font-medium hover:bg-primary-600 transition-colors"
<button
onClick={() => navigate('/backtests/new')}
className="inline-flex items-center space-x-2 px-4 py-2 bg-primary-500 text-white rounded-md text-sm font-medium hover:bg-primary-600 transition-colors"
>
Create Your First Backtest
</Link>
<PlusIcon className="w-4 h-4" />
<span>Create Your First Backtest</span>
</button>
</div>
) : (
<div className="bg-surface-secondary rounded-lg border border-border overflow-hidden">
@ -94,8 +138,13 @@ export function BacktestListPage() {
<td className="px-4 py-3 text-sm text-text-primary">
{new Date(backtest.startDate).toLocaleDateString()} - {new Date(backtest.endDate).toLocaleDateString()}
</td>
<td className={`px-4 py-3 text-sm font-medium capitalize ${getStatusColor(backtest.status)}`}>
{backtest.status}
<td className="px-4 py-3">
<div className="flex items-center space-x-2">
{getStatusIcon(backtest.status)}
<span className={`text-sm font-medium capitalize ${getStatusColor(backtest.status)}`}>
{backtest.status}
</span>
</div>
</td>
<td className="px-4 py-3 text-sm text-text-secondary">
{formatDate(backtest.createdAt)}