import { useState, useEffect } from 'react'; import { ArrowPathIcon, CircleStackIcon, CloudArrowDownIcon, ExclamationTriangleIcon, CheckCircleIcon, } from '@heroicons/react/24/outline'; import { usePipeline } from './hooks/usePipeline'; import type { PipelineOperation } from './types'; const operations: PipelineOperation[] = [ // Symbol operations { id: 'sync-qm-symbols', name: 'Sync QM Symbols', description: 'Sync symbols from QuestionsAndMethods API', endpoint: '/symbols', method: 'POST', category: 'sync', }, { id: 'sync-provider-symbols', name: 'Sync Provider Symbols', description: 'Sync symbols from a specific provider', endpoint: '/symbols/:provider', method: 'POST', category: 'sync', params: { provider: 'yahoo' }, // Default provider }, // Exchange operations { id: 'sync-qm-exchanges', name: 'Sync QM Exchanges', description: 'Sync exchanges from QuestionsAndMethods API', endpoint: '/exchanges', method: 'POST', category: 'sync', }, { id: 'sync-all-exchanges', name: 'Sync All Exchanges', description: 'Sync all exchanges with optional clear', endpoint: '/exchanges/all', method: 'POST', category: 'sync', }, // Provider mapping operations { id: 'sync-qm-provider-mappings', name: 'Sync QM Provider Mappings', description: 'Sync provider mappings from QuestionsAndMethods', endpoint: '/provider-mappings/qm', method: 'POST', category: 'sync', }, { id: 'sync-ib-exchanges', name: 'Sync IB Exchanges', description: 'Sync exchanges from Interactive Brokers', endpoint: '/provider-mappings/ib', method: 'POST', category: 'sync', }, // Maintenance operations { id: 'clear-postgresql', name: 'Clear PostgreSQL Data', description: 'Clear exchange and provider mapping data', endpoint: '/clear/postgresql', method: 'POST', category: 'maintenance', dangerous: true, }, ]; export function PipelinePage() { const { loading, error, lastJobResult, syncQMSymbols, syncProviderSymbols, syncQMExchanges, syncAllExchanges, syncQMProviderMappings, syncIBExchanges, clearPostgreSQLData, getExchangeStats, getProviderMappingStats, } = usePipeline(); const [selectedProvider, setSelectedProvider] = useState('yahoo'); const [clearFirst, setClearFirst] = useState(false); const [clearDataType, setClearDataType] = useState<'all' | 'exchanges' | 'provider_mappings'>('all'); const [stats, setStats] = useState<{ exchanges?: any; providerMappings?: any }>({}); // Load stats on mount useEffect(() => { loadStats(); }, []); const loadStats = async () => { const [exchangeStats, mappingStats] = await Promise.all([ getExchangeStats(), getProviderMappingStats(), ]); setStats({ exchanges: exchangeStats, providerMappings: mappingStats, }); }; const handleOperation = async (op: PipelineOperation) => { switch (op.id) { case 'sync-qm-symbols': await syncQMSymbols(); break; case 'sync-provider-symbols': await syncProviderSymbols(selectedProvider); break; case 'sync-qm-exchanges': await syncQMExchanges(); break; case 'sync-all-exchanges': await syncAllExchanges(clearFirst); break; case 'sync-qm-provider-mappings': await syncQMProviderMappings(); break; case 'sync-ib-exchanges': await syncIBExchanges(); break; case 'clear-postgresql': if (confirm(`Are you sure you want to clear ${clearDataType} data? This action cannot be undone.`)) { await clearPostgreSQLData(clearDataType); } break; } // Reload stats after operation await loadStats(); }; const getCategoryIcon = (category: string) => { switch (category) { case 'sync': return ; case 'maintenance': return ; default: return ; } }; const getCategoryColor = (category: string) => { switch (category) { case 'sync': return 'text-primary-400'; case 'maintenance': return 'text-warning'; default: return 'text-text-secondary'; } }; return (

Data Pipeline Management

Manage data synchronization and maintenance operations

{/* Stats Overview */} {(stats.exchanges || stats.providerMappings) && (
{stats.exchanges && (

Exchange Statistics

Total Exchanges: {stats.exchanges.totalExchanges}
Active Exchanges: {stats.exchanges.activeExchanges}
Total Provider Mappings: {stats.exchanges.totalProviderMappings}
Active Mappings: {stats.exchanges.activeProviderMappings}
)} {stats.providerMappings && (

Provider Mapping Statistics

Coverage: {stats.providerMappings.coveragePercentage?.toFixed(1)}%
Verified Mappings: {stats.providerMappings.verifiedMappings}
Auto-mapped: {stats.providerMappings.autoMappedCount}
{stats.providerMappings.mappingsByProvider && (
By Provider:
{Object.entries(stats.providerMappings.mappingsByProvider).map(([provider, count]) => ( {provider}: {String(count)} ))}
)}
)}
)} {/* Status Messages */} {error && (
{error}
)} {lastJobResult && (
{lastJobResult.success ? ( ) : ( )} {lastJobResult.message || lastJobResult.error} {lastJobResult.jobId && ( Job ID: {lastJobResult.jobId} )}
)} {/* Operations Grid */}
{/* Sync Operations */}

Sync Operations

{operations.filter(op => op.category === 'sync').map(op => (

{op.name}

{getCategoryIcon(op.category)}

{op.description}

{/* Special inputs for specific operations */} {op.id === 'sync-provider-symbols' && (
)} {op.id === 'sync-all-exchanges' && (
)}
))}
{/* Maintenance Operations */}

Maintenance Operations

{operations.filter(op => op.category === 'maintenance').map(op => (

{op.name}

{getCategoryIcon(op.category)}

{op.description}

{op.id === 'clear-postgresql' && (
)}
))}
); }