import { useState, useMemo } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { useNavigate } from "react-router-dom"; import { Loader2, AlertCircle, ClipboardCheck, CheckCircle, ExternalLink, RefreshCw, ChevronDown, ChevronUp, Rss, BookOpen, X, Globe, } from "lucide-react"; import { getTechniques, markTechniqueReviewed } from "../api/techniques"; import { listIntelItems, type IntelItem } from "../api/intel"; import { createTemplate } from "../api/test-templates"; import type { TechniqueSummary } from "../api/techniques"; import { useAuth } from "../context/AuthContext"; /* ── helpers ─────────────────────────────────────────────────────── */ const STATUS_COLORS: Record = { validated: "bg-green-500/10 text-green-400 border-green-500/20", partial: "bg-yellow-500/10 text-yellow-400 border-yellow-500/20", in_progress: "bg-blue-500/10 text-blue-400 border-blue-500/20", not_covered: "bg-red-500/10 text-red-400 border-red-500/20", not_evaluated: "bg-gray-500/10 text-gray-400 border-gray-600/20", }; const STATUS_LABELS: Record = { validated: "Validated", partial: "Partial", in_progress: "In Progress", not_covered: "Not Covered", not_evaluated: "Not Evaluated", }; function formatDate(dateStr: string | null | undefined) { if (!dateStr) return "—"; const utc = dateStr.endsWith("Z") || dateStr.includes("+") ? dateStr : dateStr + "Z"; return new Date(utc).toLocaleDateString("es-ES", { year: "numeric", month: "short", day: "numeric", }); } /* ── Create-template-from-intel modal ─────────────────────────────── */ function IntelTemplateModal({ intel, techniqueMitreId, techniqueName, onClose, onSaved, }: { intel: IntelItem; techniqueMitreId: string; techniqueName: string; onClose: () => void; onSaved: () => void; }) { const [name, setName] = useState(intel.title ?? `Test for ${techniqueMitreId}`); const [description, setDescription] = useState( intel.title ? `Based on: ${intel.title}` : "" ); const [platform, setPlatform] = useState(""); const [attackProcedure, setAttackProcedure] = useState(""); const [expectedDetection, setExpectedDetection] = useState(""); const [severity, setSeverity] = useState("medium"); const saveMutation = useMutation({ mutationFn: () => createTemplate({ mitre_technique_id: techniqueMitreId, name: name.trim(), description: description.trim() || undefined, platform: platform.trim() || undefined, attack_procedure: attackProcedure.trim() || undefined, expected_detection: expectedDetection.trim() || undefined, source_url: intel.url, severity, source: "custom", }), onSuccess: () => onSaved(), }); return (
{/* Header */}

Create Template from Intel

{/* Source article banner */}

Source: {intel.source ?? "Unknown"} · {formatDate(intel.detected_at)}

{intel.title}

Open article
{/* Technique banner */}
Technique: {techniqueMitreId} {techniqueName}
{/* Name */}
setName(e.target.value)} className="w-full rounded-lg border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-200 placeholder-gray-500 focus:border-cyan-500 focus:outline-none" />
{/* Platform + Severity */}
setPlatform(e.target.value)} placeholder="windows, linux, macos…" className="w-full rounded-lg border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-200 placeholder-gray-500 focus:border-cyan-500 focus:outline-none" />
{/* Description */}