@@ -61,6 +61,8 @@ interface AnalysisHistoryItem {
6161 full_analysis ?: any ;
6262 created_at : string ;
6363 analysis_status ?: AnalysisStatus | number ; // Support both new and legacy formats
64+ rebalance_request_id ?: string | null ;
65+ is_canceled ?: boolean ;
6466}
6567
6668interface RunningAnalysisItem {
@@ -235,10 +237,10 @@ export default function UnifiedAnalysisHistory() {
235237 const startOfDay = new Date ( year , month - 1 , day , 0 , 0 , 0 , 0 ) ;
236238 const endOfDay = new Date ( year , month - 1 , day , 23 , 59 , 59 , 999 ) ;
237239
238- // Query only analyses from the selected date
240+ // Query only analyses from the selected date (summary fields only)
239241 const { data, error } = await supabase
240242 . from ( 'analysis_history' )
241- . select ( '* ' )
243+ . select ( 'id,ticker,analysis_date,decision,confidence,agent_insights,created_at,analysis_status,rebalance_request_id,is_canceled ' )
242244 . eq ( 'user_id' , user . id )
243245 . gte ( 'created_at' , startOfDay . toISOString ( ) )
244246 . lte ( 'created_at' , endOfDay . toISOString ( ) )
@@ -266,61 +268,92 @@ export default function UnifiedAnalysisHistory() {
266268 throw error ;
267269 }
268270
269- // Separate running, completed, and canceled analyses based on database data
270- const runningAnalyses : RunningAnalysisItem [ ] = [ ] ;
271+ const baseRows = data ?? [ ] ;
272+ const runningIds : string [ ] = [ ] ;
273+ const runningBase : Array < Omit < RunningAnalysisItem , 'full_analysis' > > = [ ] ;
271274 const completedAnalyses : AnalysisHistoryItem [ ] = [ ] ;
272275 const canceledAnalyses : AnalysisHistoryItem [ ] = [ ] ;
273276
274- for ( const item of data || [ ] ) {
275- // Use analysis_status field if available, otherwise fall back to old logic
276- if ( 'analysis_status' in item ) {
277- // Convert legacy numeric status to new string format
278- const status : AnalysisStatus = typeof item . analysis_status === 'number'
279- ? convertLegacyAnalysisStatus ( item . analysis_status )
280- : item . analysis_status as AnalysisStatus ;
281-
282- if ( status === ANALYSIS_STATUS . RUNNING || status === ANALYSIS_STATUS . PENDING ) {
283- runningAnalyses . push ( {
284- id : item . id ,
285- ticker : item . ticker ,
286- created_at : item . created_at ,
287- full_analysis : item . full_analysis ,
288- agent_insights : item . agent_insights , // Add this!
289- rebalance_request_id : item . rebalance_request_id ,
290- status : status
291- } ) ;
292- } else if ( status === ANALYSIS_STATUS . COMPLETED ) {
293- completedAnalyses . push ( item ) ;
294- } else if ( status === ANALYSIS_STATUS . ERROR || status === ANALYSIS_STATUS . CANCELLED ) {
295- // Show canceled/error analyses in the canceled section
296- canceledAnalyses . push ( {
297- ...item ,
298- decision : status === ANALYSIS_STATUS . ERROR ? 'ERROR' : 'CANCELED' ,
299- confidence : item . confidence || 0
300- } ) ;
301- }
302- } else {
303- // Fall back to old logic for backward compatibility
304- const hasAgentInsights = item . agent_insights && Object . keys ( item . agent_insights ) . length > 0 ;
305- const isRunning = item . analysis_status === ANALYSIS_STATUS . RUNNING ||
306- ( item . confidence === 0 && ! hasAgentInsights ) ;
307-
308- if ( isRunning ) {
309- runningAnalyses . push ( {
310- id : item . id ,
311- ticker : item . ticker ,
312- created_at : item . created_at ,
313- full_analysis : item . full_analysis ,
314- rebalance_request_id : item . rebalance_request_id ,
315- status : ANALYSIS_STATUS . RUNNING // Default to running for fallback logic
316- } ) ;
317- } else if ( ( item . confidence > 0 || hasAgentInsights ) && item . decision && [ 'BUY' , 'SELL' , 'HOLD' ] . includes ( item . decision ) ) {
318- completedAnalyses . push ( item ) ;
277+ for ( const item of baseRows ) {
278+ let status : AnalysisStatus | null = null ;
279+
280+ if ( typeof item . analysis_status === 'number' ) {
281+ status = convertLegacyAnalysisStatus ( item . analysis_status ) ;
282+ } else if ( typeof item . analysis_status === 'string' ) {
283+ status = item . analysis_status . toLowerCase ( ) as AnalysisStatus ;
284+ }
285+
286+ if ( ! status ) {
287+ const hasAgentInsights = item . agent_insights && Object . keys ( item . agent_insights || { } ) . length > 0 ;
288+
289+ if ( item . is_canceled ) {
290+ status = ANALYSIS_STATUS . CANCELLED ;
291+ } else if ( item . confidence === 0 && ! hasAgentInsights ) {
292+ status = ANALYSIS_STATUS . RUNNING ;
293+ } else if ( item . decision && [ 'BUY' , 'SELL' , 'HOLD' ] . includes ( item . decision ) ) {
294+ status = ANALYSIS_STATUS . COMPLETED ;
295+ } else {
296+ status = ANALYSIS_STATUS . RUNNING ;
319297 }
320298 }
299+
300+ if ( status === ANALYSIS_STATUS . RUNNING || status === ANALYSIS_STATUS . PENDING ) {
301+ runningIds . push ( item . id ) ;
302+ runningBase . push ( {
303+ id : item . id ,
304+ ticker : item . ticker ,
305+ created_at : item . created_at ,
306+ agent_insights : item . agent_insights ,
307+ rebalance_request_id : item . rebalance_request_id || undefined ,
308+ status
309+ } ) ;
310+ } else if ( status === ANALYSIS_STATUS . COMPLETED ) {
311+ completedAnalyses . push ( {
312+ id : item . id ,
313+ ticker : item . ticker ,
314+ analysis_date : item . analysis_date ,
315+ decision : item . decision ,
316+ confidence : item . confidence ,
317+ agent_insights : item . agent_insights ,
318+ created_at : item . created_at ,
319+ analysis_status : status ,
320+ rebalance_request_id : item . rebalance_request_id || undefined
321+ } ) ;
322+ } else if ( status === ANALYSIS_STATUS . ERROR || status === ANALYSIS_STATUS . CANCELLED ) {
323+ canceledAnalyses . push ( {
324+ id : item . id ,
325+ ticker : item . ticker ,
326+ analysis_date : item . analysis_date ,
327+ decision : status === ANALYSIS_STATUS . ERROR ? 'ERROR' : 'CANCELED' ,
328+ confidence : item . confidence || 0 ,
329+ agent_insights : item . agent_insights ,
330+ created_at : item . created_at ,
331+ analysis_status : status ,
332+ rebalance_request_id : item . rebalance_request_id || undefined
333+ } ) ;
334+ }
321335 }
322336
323- setRunningAnalyses ( runningAnalyses ) ;
337+ let runningDetailsMap = new Map < string , any > ( ) ;
338+ if ( runningIds . length > 0 ) {
339+ const { data : runningDetails , error : runningDetailsError } = await supabase
340+ . from ( 'analysis_history' )
341+ . select ( 'id, full_analysis' )
342+ . in ( 'id' , runningIds ) ;
343+
344+ if ( ! runningDetailsError && runningDetails ) {
345+ runningDetailsMap = new Map (
346+ runningDetails . map ( detail => [ detail . id , detail . full_analysis ] )
347+ ) ;
348+ }
349+ }
350+
351+ const hydratedRunningAnalyses : RunningAnalysisItem [ ] = runningBase . map ( item => ( {
352+ ...item ,
353+ full_analysis : runningDetailsMap . get ( item . id ) || null
354+ } ) ) ;
355+
356+ setRunningAnalyses ( hydratedRunningAnalyses ) ;
324357 setHistory ( completedAnalyses ) ;
325358 setCanceledAnalyses ( canceledAnalyses ) ;
326359
@@ -390,7 +423,7 @@ export default function UnifiedAnalysisHistory() {
390423 // Only fetch the specific running analyses to check their status
391424 const { data, error } = await supabase
392425 . from ( 'analysis_history' )
393- . select ( '* ' )
426+ . select ( 'id,analysis_status,full_analysis,agent_insights,created_at ' )
394427 . eq ( 'user_id' , user . id )
395428 . in ( 'id' , runningIds )
396429 . gte ( 'created_at' , startOfDay . toISOString ( ) )
0 commit comments