HyperCluster/Fara-BrowserUse
5
1import { useAgentStore } from '@/stores/agentStore';
2import { FinalStep } from '@/types/agent';
3import AccessTimeIcon from '@mui/icons-material/AccessTime';
4import CheckIcon from '@mui/icons-material/Check';
5import CloseIcon from '@mui/icons-material/Close';
6import HourglassEmptyIcon from '@mui/icons-material/HourglassEmpty';
7import StopCircleIcon from '@mui/icons-material/StopCircle';
8import { Box, Card, CardContent, Typography } from '@mui/material';
9import React from 'react';
10
11interface FinalStepCardProps {
12 finalStep: FinalStep;
13 isActive?: boolean;
14}
15
16export const FinalStepCard: React.FC<FinalStepCardProps> = ({ finalStep, isActive = false }) => {
17 const setSelectedStepIndex = useAgentStore((state) => state.setSelectedStepIndex);
18
19 const getStatusConfig = () => {
20 switch (finalStep.type) {
21 case 'success':
22 return {
23 icon: <CheckIcon sx={{ fontSize: 20, color: 'success.main' }} />,
24 label: 'Task completed',
25 color: 'success',
26 };
27 case 'stopped':
28 return {
29 icon: <StopCircleIcon sx={{ fontSize: 20, color: 'warning.main' }} />,
30 label: 'Task stopped',
31 color: 'warning',
32 };
33 case 'max_steps_reached':
34 return {
35 icon: <HourglassEmptyIcon sx={{ fontSize: 20, color: 'warning.main' }} />,
36 label: 'Max steps reached',
37 color: 'warning',
38 };
39 case 'sandbox_timeout':
40 return {
41 icon: <AccessTimeIcon sx={{ fontSize: 20, color: 'error.main' }} />,
42 label: 'Sandbox timeout',
43 color: 'error',
44 };
45 case 'failure':
46 default:
47 return {
48 icon: <CloseIcon sx={{ fontSize: 20, color: 'error.main' }} />,
49 label: 'Task failed',
50 color: 'error',
51 };
52 }
53 };
54
55 const statusConfig = getStatusConfig();
56
57 const handleClick = () => {
58 // Clicking on final step goes to live mode (null)
59 setSelectedStepIndex(null);
60 };
61
62 return (
63 <Card
64 elevation={0}
65 onClick={handleClick}
66 sx={{
67 backgroundColor: 'background.paper',
68 border: '1px solid',
69 borderColor: (theme) => `${isActive
70 ? theme.palette[statusConfig.color].main
71 : theme.palette.divider} !important`,
72 borderRadius: 1.5,
73 transition: 'all 0.2s ease',
74 cursor: 'pointer',
75 boxShadow: isActive
76 ? (theme) => `0 2px 8px ${theme.palette.mode === 'dark'
77 ? `rgba(${statusConfig.color === 'success' ? '102, 187, 106' : statusConfig.color === 'error' ? '244, 67, 54' : '255, 152, 0'}, 0.3)`
78 : `rgba(${statusConfig.color === 'success' ? '102, 187, 106' : statusConfig.color === 'error' ? '244, 67, 54' : '255, 152, 0'}, 0.2)`}`
79 : 'none',
80 '&:hover': {
81 borderColor: (theme) => `${theme.palette[statusConfig.color].main} !important`,
82 boxShadow: (theme) => `0 2px 8px ${theme.palette.mode === 'dark'
83 ? `rgba(${statusConfig.color === 'success' ? '102, 187, 106' : statusConfig.color === 'error' ? '244, 67, 54' : '255, 152, 0'}, 0.2)`
84 : `rgba(${statusConfig.color === 'success' ? '102, 187, 106' : statusConfig.color === 'error' ? '244, 67, 54' : '255, 152, 0'}, 0.1)`}`,
85 },
86 }}
87 >
88 <CardContent sx={{ p: 1.5, '&:last-child': { pb: 1.5 } }}>
89 {/* Header with icon */}
90 <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>
91 {statusConfig.icon}
92 <Typography
93 sx={{
94 fontSize: '0.85rem',
95 fontWeight: 700,
96 color: `${statusConfig.color}.main`,
97 }}
98 >
99 {statusConfig.label}
100 </Typography>
101 </Box>
102 </CardContent>
103 </Card>
104 );
105};
106 