Fix score refresh, add granular fetch and live job status
Scores never updated ("101d ago"): get_score only recomputes stale/
missing dimensions, but nothing marked them stale on new data, and there
was no scheduled scoring job.
- Fetch endpoint force-recomputes dimensions + composite.
- Scheduled scan (scan_all_tickers) refreshes scores per ticker, so
scores stay current globally, not just on manual fetch.
Granular fetch: /ingestion/fetch accepts a sources filter; the freshness
bar gets a per-row refresh button (OHLCV/Sentiment/Fundamentals fetch
that provider only — marked paid; S/R/Scores recompute for free). Header
button is now "Fetch All".
Job visibility: GET /jobs/running (any user) + sidebar live indicator
showing running scheduled jobs with progress, polled every 10s.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { fetchData, type FetchDataResult } from '../api/ingestion';
|
||||
import { fetchData, type FetchDataResult, type FetchSelector } from '../api/ingestion';
|
||||
import { useToast } from '../components/ui/Toast';
|
||||
import { summarizeIngestionResult } from '../lib/ingestionStatus';
|
||||
|
||||
@@ -8,14 +8,26 @@ interface UseFetchSymbolDataOptions {
|
||||
invalidatePipelineReadiness?: boolean;
|
||||
}
|
||||
|
||||
export interface FetchVars {
|
||||
symbol: string;
|
||||
sources?: FetchSelector;
|
||||
}
|
||||
|
||||
type FetchArg = string | FetchVars;
|
||||
|
||||
const argSymbol = (arg: FetchArg): string => (typeof arg === 'string' ? arg : arg.symbol);
|
||||
|
||||
export function useFetchSymbolData(options: UseFetchSymbolDataOptions = {}) {
|
||||
const { includeSymbolPrefix = false, invalidatePipelineReadiness = false } = options;
|
||||
const queryClient = useQueryClient();
|
||||
const { addToast } = useToast();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (symbol: string) => fetchData(symbol),
|
||||
onSuccess: (result: FetchDataResult, symbol: string) => {
|
||||
// Accepts either a bare symbol (fetch all) or { symbol, sources } (granular)
|
||||
mutationFn: (arg: FetchArg) =>
|
||||
typeof arg === 'string' ? fetchData(arg) : fetchData(arg.symbol, arg.sources),
|
||||
onSuccess: (result: FetchDataResult, arg: FetchArg) => {
|
||||
const symbol = argSymbol(arg);
|
||||
const normalized = symbol.toUpperCase();
|
||||
const summary = summarizeIngestionResult(result, normalized);
|
||||
const toastMessage = includeSymbolPrefix
|
||||
@@ -33,8 +45,8 @@ export function useFetchSymbolData(options: UseFetchSymbolDataOptions = {}) {
|
||||
queryClient.invalidateQueries({ queryKey: ['admin', 'pipeline-readiness'] });
|
||||
}
|
||||
},
|
||||
onError: (err: Error, symbol: string) => {
|
||||
const normalized = symbol.toUpperCase();
|
||||
onError: (err: Error, arg: FetchArg) => {
|
||||
const normalized = argSymbol(arg).toUpperCase();
|
||||
const prefix = includeSymbolPrefix ? `${normalized}: ` : '';
|
||||
addToast('error', `${prefix}${err.message || 'Failed to fetch data'}`);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user