({ evalItem, onDelete }: EvalCardProps)
| 194 | } |
| 195 | |
| 196 | function EvalCard({ evalItem, onDelete }: EvalCardProps) { |
| 197 | const [showMenu, setShowMenu] = useState(false); |
| 198 | |
| 199 | const statusConfig = STATUS_CONFIG[evalItem.status]; |
| 200 | const typeConfig = TYPE_CONFIG[evalItem.type]; |
| 201 | const StatusIcon = statusConfig.icon; |
| 202 | const TypeIcon = typeConfig.icon; |
| 203 | |
| 204 | const scoreColor = evalItem.score !== undefined |
| 205 | ? evalItem.score >= 0.8 ? 'text-[var(--color-success)]' |
| 206 | : evalItem.score >= 0.5 ? 'text-[var(--color-warning)]' |
| 207 | : 'text-[var(--color-error)]' |
| 208 | : ''; |
| 209 | |
| 210 | return ( |
| 211 | <div className="bg-[var(--color-surface)] border border-[var(--color-border)] rounded-lg p-4 hover:border-[var(--color-primary)]/50 transition-colors"> |
| 212 | <div className="flex items-start justify-between"> |
| 213 | {/* Left */} |
| 214 | <div className="flex items-start gap-4 flex-1 min-w-0"> |
| 215 | {/* Icon */} |
| 216 | <div className="w-10 h-10 rounded-lg bg-[var(--color-primary)]/10 flex items-center justify-center flex-shrink-0"> |
| 217 | <TypeIcon className="w-5 h-5 text-[var(--color-primary)]" /> |
| 218 | </div> |
| 219 | |
| 220 | {/* Info */} |
| 221 | <div className="flex-1 min-w-0"> |
| 222 | <div className="flex items-center gap-2"> |
| 223 | <h3 className="font-medium text-[var(--color-text-primary)] truncate"> |
| 224 | {evalItem.name} |
| 225 | </h3> |
| 226 | <span className="px-2 py-0.5 text-xs rounded-full bg-[var(--color-surface-elevated)] text-[var(--color-text-muted)]"> |
| 227 | {typeConfig.label} |
| 228 | </span> |
| 229 | </div> |
| 230 | <p className="text-xs text-[var(--color-text-muted)] font-mono mt-1"> |
| 231 | {evalItem.id.slice(0, 12)}... |
| 232 | </p> |
| 233 | </div> |
| 234 | </div> |
| 235 | |
| 236 | {/* Right */} |
| 237 | <div className="flex items-center gap-4"> |
| 238 | {/* Score */} |
| 239 | {evalItem.score !== undefined && ( |
| 240 | <div className="text-right"> |
| 241 | <div className={cn('text-lg font-semibold', scoreColor)}> |
| 242 | {(evalItem.score * 100).toFixed(1)}% |
| 243 | </div> |
| 244 | <div className="text-xs text-[var(--color-text-muted)]">评分</div> |
| 245 | </div> |
| 246 | )} |
| 247 | |
| 248 | {/* Status */} |
| 249 | <div className="flex items-center gap-2 min-w-[80px]"> |
| 250 | <StatusIcon className={cn( |
| 251 | 'w-4 h-4', |
| 252 | statusConfig.color, |
| 253 | evalItem.status === 'running' && 'animate-spin' |
nothing calls this directly
no test coverage detected