import { Link, useNavigate } from 'react-router-dom'; import { extractApiError } from '@/api/client'; import { useAuth } from '@/hooks/useAuth'; import { useEngagementSimulations } from '@/hooks/useSimulations'; import { LoadingState } from './LoadingState'; import { ErrorState } from './ErrorState'; import { EmptyState } from './EmptyState'; import { SimulationStatusBadge } from './SimulationStatusBadge'; interface SimulationListProps { engagementId: number; } function formatDate(value: string | null): string { if (!value) return '—'; return value.replace('T', ' ').slice(0, 16); } export function SimulationList({ engagementId }: SimulationListProps): JSX.Element { const { data, isLoading, isError, error, refetch } = useEngagementSimulations(engagementId); const { canEditEngagements } = useAuth(); const navigate = useNavigate(); if (isLoading) return ; if (isError) { return ( refetch()} /> ); } if (!data || data.length === 0) { return ( New simulation ) : undefined } /> ); } return (

Simulations

{canEditEngagements ? ( New simulation ) : null}
{data.map((sim) => ( navigate(`/engagements/${engagementId}/simulations/${sim.id}/edit`) } > ))}
Name MITRE Status Executed at
e.stopPropagation()} > {sim.name} {(() => { const items = [ ...(sim.tactics ?? []).map((t) => t.id), ...sim.techniques.map((t) => t.id), ]; if (items.length === 0) return '—'; if (items.length === 1) return items[0]; return `${items[0]} +${items.length - 1}`; })()} {formatDate(sim.executed_at)}
); }