diff --git a/agentic_ai/workflow/fraud_detection/backend.py b/agentic_ai/workflow/fraud_detection/backend.py index f384ae54e..e15446a07 100644 --- a/agentic_ai/workflow/fraud_detection/backend.py +++ b/agentic_ai/workflow/fraud_detection/backend.py @@ -204,6 +204,14 @@ async def broadcast(self, message: dict): timestamp=datetime.now().isoformat(), severity="high", ), + "ALERT-004": SuspiciousActivityAlert( + alert_id="ALERT-004", + customer_id=4, + alert_type="routine_check", + description="Routine security check - password changed from usual device", + timestamp=datetime.now().isoformat(), + severity="low", + ), } diff --git a/agentic_ai/workflow/fraud_detection/ui/src/App.jsx b/agentic_ai/workflow/fraud_detection/ui/src/App.jsx index 6144d9d68..c1aed94c1 100644 --- a/agentic_ai/workflow/fraud_detection/ui/src/App.jsx +++ b/agentic_ai/workflow/fraud_detection/ui/src/App.jsx @@ -68,8 +68,14 @@ function App() { try { const event = lastMessage; - // Add to event log - setEvents((prev) => [...prev, event]); + // Add to event log - prevent duplicates by checking timestamp + type + executor_id + setEvents((prev) => { + const eventKey = `${event.timestamp}-${event.type || event.event_type}-${event.executor_id || ''}`; + const isDuplicate = prev.some( + (e) => `${e.timestamp}-${e.type || e.event_type}-${e.executor_id || ''}` === eventKey + ); + return isDuplicate ? prev : [...prev, event]; + }); // Handle workflow initialization if (event.type === 'workflow_initializing') { @@ -212,7 +218,7 @@ function App() { {/* Right Column - Event Log */} - + diff --git a/agentic_ai/workflow/fraud_detection/ui/src/components/AnalystDecisionPanel.jsx b/agentic_ai/workflow/fraud_detection/ui/src/components/AnalystDecisionPanel.jsx index 0c6ce849d..1ace37d1a 100644 --- a/agentic_ai/workflow/fraud_detection/ui/src/components/AnalystDecisionPanel.jsx +++ b/agentic_ai/workflow/fraud_detection/ui/src/components/AnalystDecisionPanel.jsx @@ -58,10 +58,10 @@ function AnalystDecisionPanel({ decision, onSubmit }) { - - - Analyst Review Required + + + Analyst Review Required - - + + Human Decision Needed - - The workflow is paused pending your review - - + {/* Risk Assessment */} - + Risk Assessment - - Risk Score: + + Risk Score: - - Alert ID: - + + Alert ID: + {/* Reasoning */} {decision.data?.reasoning && ( - + AI Analysis - - + + {decision.data.reasoning} @@ -124,7 +122,7 @@ function AnalystDecisionPanel({ decision, onSubmit }) { {/* Recommended Action */} - + Recommended Action opt.value === decision.data?.recommended_action) ?.color || 'default' } - size="medium" + size="small" + sx={{ height: 20, fontSize: '0.7rem' }} /> - + {/* Decision Form */} - - Your Decision + + Your Decision setSelectedAlertId(e.target.value)} disabled={workflowRunning} + sx={{ fontSize: '0.875rem' }} > {alerts.map((alert) => ( - - + + {getSeverityIcon(alert.severity)} - + {alert.alert_id} - + {alert.alert_type} @@ -82,6 +83,7 @@ function ControlPanel({ alerts, onStartWorkflow, workflowRunning, selectedAlert label={alert.severity} size="small" color={getSeverityColor(alert.severity)} + sx={{ height: 18, fontSize: '0.7rem' }} /> @@ -90,23 +92,25 @@ function ControlPanel({ alerts, onStartWorkflow, workflowRunning, selectedAlert {selectedAlertId && !workflowRunning && ( - - + + Description: - + {alerts.find((a) => a.alert_id === selectedAlertId)?.description} - + a.alert_id === selectedAlertId)?.customer_id}`} size="small" variant="outlined" + sx={{ height: 18, fontSize: '0.7rem' }} /> a.alert_id === selectedAlertId)?.alert_type} size="small" variant="outlined" + sx={{ height: 18, fontSize: '0.7rem' }} /> @@ -114,22 +118,22 @@ function ControlPanel({ alerts, onStartWorkflow, workflowRunning, selectedAlert {selectedAlert && workflowRunning && ( - - + + Active Workflow - + Processing {selectedAlert.alert_id} diff --git a/agentic_ai/workflow/fraud_detection/ui/src/components/EventLog.jsx b/agentic_ai/workflow/fraud_detection/ui/src/components/EventLog.jsx index cf8491dc0..66cd3413c 100644 --- a/agentic_ai/workflow/fraud_detection/ui/src/components/EventLog.jsx +++ b/agentic_ai/workflow/fraud_detection/ui/src/components/EventLog.jsx @@ -107,10 +107,10 @@ function EventLog({ events }) { }; return ( - - - Event Log - + + + Event Log + {events.length} events @@ -120,13 +120,27 @@ function EventLog({ events }) { sx={{ flex: 1, overflow: 'auto', - px: 1, + px: 0.5, py: 0, + minHeight: 0, + '&::-webkit-scrollbar': { + width: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: 'grey.100', + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: 'grey.400', + borderRadius: '4px', + '&:hover': { + backgroundColor: 'grey.600', + }, + }, }} > {events.length === 0 ? ( - - + + No events yet. Start a workflow to see events. @@ -135,38 +149,38 @@ function EventLog({ events }) { - - {getEventIcon(event)} + + {React.cloneElement(getEventIcon(event), { fontSize: 'small' })} - + + {getEventTitle(event)} } secondary={ - + {formatTime(event.timestamp)} } /> - {index < events.length - 1 && } + {index < events.length - 1 && } )) )}