import { useQueryClient } from '@tanstack/react-query'; import { usePipelineReadiness } from '../../hooks/useAdmin'; import { useFetchSymbolData } from '../../hooks/useFetchSymbolData'; import { formatDateTime } from '../../lib/format'; import { SkeletonTable } from '../ui/Skeleton'; function scoreBadge(score: number | null) { if (score === null) return ; const cls = score >= 60 ? 'text-emerald-400' : score >= 40 ? 'text-amber-400' : 'text-red-400'; return {score.toFixed(0)}; } export function PipelineReadinessPanel() { const queryClient = useQueryClient(); const { data, isLoading, isError, error, isFetching } = usePipelineReadiness(); const fetchMutation = useFetchSymbolData({ includeSymbolPrefix: true, invalidatePipelineReadiness: true, }); if (isLoading) return ; if (isError) return

{(error as Error)?.message || 'Failed to load pipeline readiness'}

; const rows = data ?? []; return (

Pipeline Readiness

Shows why tickers may be missing in scanner/rankings and what is incomplete.

{rows.length === 0 ? (

No tickers available.

) : (
{rows.map((row) => ( ))}
Symbol OHLCV Dims S/R Scanner Missing Reasons Action
{row.symbol}
{row.ohlcv_bars} bars
{row.ohlcv_last_date ? formatDateTime(row.ohlcv_last_date) : '—'}
{scoreBadge(row.dimensions.technical)} {scoreBadge(row.dimensions.sr_quality)} {scoreBadge(row.dimensions.sentiment)} {scoreBadge(row.dimensions.fundamental)} {scoreBadge(row.dimensions.momentum)}
T SR S F M
{row.sr_level_count} {row.ready_for_scanner ? 'Ready' : 'Blocked'}
setups: {row.trade_setup_count}
{row.missing_reasons.length ? row.missing_reasons.join(', ') : none}
)}
); }