import { useState, useRef } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { Loader2, AlertCircle, RefreshCw, Server, Database, HardDrive, Clock, CheckCircle, XCircle, Shield, Search, FlaskConical, Plus, ToggleLeft, ToggleRight, BarChart3, X, Download, Upload, PackageOpen, } from "lucide-react"; import client from "../api/client"; import { triggerMitreSync, triggerIntelScan, getSchedulerStatus, type SyncMitreResponse, type IntelScanResponse, } from "../api/system"; import { getTemplateStats, getAllTemplates, getTemplateById, createTemplate, updateTemplate, toggleTemplateActive, bulkActivateTemplates, type TemplateStats, type CreateTemplatePayload, } from "../api/test-templates"; import type { TestTemplate } from "../types/models"; export default function SystemPage() { const queryClient = useQueryClient(); const [syncResult, setSyncResult] = useState(null); const [intelResult, setIntelResult] = useState(null); const [showCreateForm, setShowCreateForm] = useState(false); const [bulkConfirm, setBulkConfirm] = useState<"activate" | "deactivate" | null>(null); const [selectedTemplateId, setSelectedTemplateId] = useState(null); // ── Existing queries ───────────────────────────────────────────── const { data: schedulerStatus, isLoading: statusLoading, error: statusError, } = useQuery({ queryKey: ["scheduler-status"], queryFn: getSchedulerStatus, refetchInterval: 30000, }); // ── Template queries ───────────────────────────────────────────── const { data: templateStats, isLoading: statsLoading, } = useQuery({ queryKey: ["template-stats"], queryFn: getTemplateStats, }); const { data: templates, isLoading: templatesLoading, } = useQuery({ queryKey: ["templates-admin"], queryFn: () => getAllTemplates({ limit: 200 }), }); const { data: selectedTemplate, isLoading: selectedTemplateLoading, } = useQuery({ queryKey: ["template-detail", selectedTemplateId], queryFn: () => getTemplateById(selectedTemplateId!), enabled: !!selectedTemplateId, }); // ── Mutations ──────────────────────────────────────────────────── const mitreSyncMutation = useMutation({ mutationFn: triggerMitreSync, onSuccess: (data) => { setSyncResult(data); queryClient.invalidateQueries({ queryKey: ["techniques"] }); queryClient.invalidateQueries({ queryKey: ["metrics"] }); }, }); const intelScanMutation = useMutation({ mutationFn: triggerIntelScan, onSuccess: (data) => { setIntelResult(data); queryClient.invalidateQueries({ queryKey: ["techniques"] }); }, }); const bulkActivateMutation = useMutation({ mutationFn: (activate: boolean) => bulkActivateTemplates(activate), onSuccess: () => { setBulkConfirm(null); queryClient.invalidateQueries({ queryKey: ["templates-admin"] }); queryClient.invalidateQueries({ queryKey: ["template-stats"] }); queryClient.invalidateQueries({ queryKey: ["test-templates"] }); }, }); const toggleActiveMutation = useMutation({ mutationFn: (id: string) => toggleTemplateActive(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["templates-admin"] }); queryClient.invalidateQueries({ queryKey: ["template-stats"] }); queryClient.invalidateQueries({ queryKey: ["test-templates"] }); }, }); const createTemplateMutation = useMutation({ mutationFn: (payload: CreateTemplatePayload) => createTemplate(payload), onSuccess: () => { setShowCreateForm(false); queryClient.invalidateQueries({ queryKey: ["templates-admin"] }); queryClient.invalidateQueries({ queryKey: ["template-stats"] }); queryClient.invalidateQueries({ queryKey: ["test-templates"] }); }, }); const updateTemplateMutation = useMutation({ mutationFn: ({ id, payload }: { id: string; payload: Partial }) => updateTemplate(id, payload), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["templates-admin"] }); queryClient.invalidateQueries({ queryKey: ["test-templates"] }); queryClient.invalidateQueries({ queryKey: ["template-detail", selectedTemplateId] }); }, }); const formatNextRun = (dateStr: string | null) => { if (!dateStr) return "Not scheduled"; const date = new Date(dateStr); return date.toLocaleString("en-US", { dateStyle: "medium", timeStyle: "short", }); }; return (
{/* Header */}

System Administration

Manage synchronization jobs, templates, and system status

{/* Actions Grid */}
{/* MITRE Sync */}

MITRE ATT&CK Sync

Synchronize techniques from the MITRE ATT&CK framework via TAXII or GitHub fallback.

{schedulerStatus && (
Next automatic sync: {formatNextRun( schedulerStatus.jobs.find((j) => j.id === "mitre_sync")?.next_run_time || null )}
)} {syncResult && (
{syncResult.status === "started" ? "Sync Started" : "Sync Complete"}

{syncResult.message}

)} {mitreSyncMutation.isError && (
Sync failed: {(mitreSyncMutation.error as Error)?.message}
)}
{/* Intel Scan */}

Threat Intel Scan

Scan RSS feeds and security blogs for new threat intelligence related to techniques.

{schedulerStatus && (
Next automatic scan: {formatNextRun( schedulerStatus.jobs.find((j) => j.id === "intel_scan")?.next_run_time || null )}
)} {intelResult && (
Scan Complete
New intel items: {intelResult.new_items}
)} {intelScanMutation.isError && (
Scan failed: {(intelScanMutation.error as Error)?.message}
)}
{/* ──────────────────────────────────────────────────────────────── TEMPLATE ADMINISTRATION (T-124) ──────────────────────────────────────────────────────────────── */} {/* Template Catalog Stats */}
{/* Template Catalog Stats */}

Catalog Statistics

Overview of the test template catalog.

{statsLoading ? (
) : templateStats ? (
{/* Totals */}

{templateStats.total}

Total

{templateStats.active}

Active

{templateStats.inactive}

Inactive

{/* By source */}

By Source

{Object.entries(templateStats.by_source).map(([source, count]) => ( {source.replace(/_/g, " ")} {count} ))} {Object.keys(templateStats.by_source).length === 0 && ( No templates yet )}
{/* By platform */}

By Platform

{Object.entries(templateStats.by_platform).map(([platform, count]) => ( {platform} {count} ))} {Object.keys(templateStats.by_platform).length === 0 && ( No templates yet )}
) : null}
{/* Create Custom Template Form (modal-style inline) */} {showCreateForm && ( setShowCreateForm(false)} onSubmit={(payload) => createTemplateMutation.mutate(payload)} isPending={createTemplateMutation.isPending} error={createTemplateMutation.isError ? (createTemplateMutation.error as Error)?.message : null} /> )} {/* Bulk Activate Confirmation Modal */} {bulkConfirm && (

{bulkConfirm === "activate" ? "Activate All Templates" : "Deactivate All Templates"}

{bulkConfirm === "activate" ? "This will activate ALL templates in the catalog, including previously deactivated ones. All templates will become available for test creation." : "This will deactivate ALL templates in the catalog. No templates will be available for test creation until reactivated."}

This action affects all {templateStats?.total || 0} templates.

)} {/* Templates Management Table */}

Manage Templates

{templatesLoading ? (
) : templates && templates.length > 0 ? (
{(templates as TestTemplate[]).map((tpl) => ( ))}
Name Technique Source Platform Status Action
{tpl.mitre_technique_id} {tpl.source.replace(/_/g, " ")} {tpl.platform || "-"} {tpl.is_active ? "Active" : "Inactive"}
) : (
No templates found. Import from Atomic Red Team or create a custom template.
)}
{/* System Information */}

System Information

Backend

Online

PostgreSQL

Connected

MinIO Storage

Available

Scheduler

{statusLoading ? "Checking..." : schedulerStatus?.running ? "Running" : "Stopped"}

{/* Scheduled Jobs */}

Scheduled Jobs

{statusLoading ? (
) : statusError ? (
Failed to load scheduler status
) : (
{schedulerStatus?.jobs.map((job) => ( ))} {(!schedulerStatus?.jobs || schedulerStatus.jobs.length === 0) && ( )}
Job ID Name Next Run Status
{job.id} {job.name} {formatNextRun(job.next_run_time)} {job.next_run_time ? ( Scheduled ) : ( Pending )}
No scheduled jobs found
)}
{/* Export / Import Configuration */} {/* Version Info */}

Version Information

Platform
Aegis v0.1.0
Backend
FastAPI + Python 3.11
Frontend
React 19 + TypeScript
Database
PostgreSQL 15
{/* Template Detail Modal */} {selectedTemplateId && ( selectedTemplateLoading ? (
) : selectedTemplate ? ( setSelectedTemplateId(null)} onSave={(id, payload) => updateTemplateMutation.mutate({ id, payload })} onToggleActive={(id) => toggleActiveMutation.mutate(id)} isSaving={updateTemplateMutation.isPending} isToggling={toggleActiveMutation.isPending} /> ) : null )}
); } /* ── Export / Import Configuration ───────────────────────────────── */ function ExportImportSection() { const fileRef = useRef(null); const [importing, setImporting] = useState(false); const [importResult, setImportResult] = useState<{ status: string; summary: Record; warnings: string[]; } | null>(null); const [importError, setImportError] = useState(null); const handleExport = async () => { try { const resp = await client.get("/admin/export-config", { responseType: "blob", }); const url = URL.createObjectURL(resp.data); const a = document.createElement("a"); a.href = url; const date = new Date().toISOString().slice(0, 10); a.download = `aegis-config-${date}.json`; a.click(); URL.revokeObjectURL(url); } catch (e) { alert("Export failed: " + (e as Error).message); } }; const handleImportFile = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; e.target.value = ""; setImportError(null); setImportResult(null); setImporting(true); try { const text = await file.text(); const json = JSON.parse(text); const resp = await client.post("/admin/import-config", json); setImportResult(resp.data); } catch (err: unknown) { const msg = (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail ?? (err as Error)?.message ?? "Import failed"; setImportError(String(msg)); } finally { setImporting(false); } }; return (

Configuration Export / Import

Export all platform configuration to a JSON file for backup or migration. Import restores settings, webhooks, custom templates and users on a fresh instance.

{/* What is exported */}

What is included

{[ ["✅", "Email & Jira settings"], ["✅", "SSO / SAML configuration"], ["✅", "Webhooks"], ["✅", "Scoring weights"], ["✅", "Custom test templates"], ["✅", "Users (roles & status)"], ["🔒", "Passwords / API tokens → REDACTED"], ["❌", "Tests, campaigns, techniques data"], ].map(([icon, text]) => (
{icon} {text}
))}
{/* Actions */}
{/* Import result */} {importResult && (

Import completed successfully

{Object.entries(importResult.summary).map(([key, val]) => (
{key.replace(/_/g, " ")} {val}
))}
{importResult.warnings.length > 0 && (
    {importResult.warnings.map((w) =>
  • {w}
  • )}
)}
)} {importError && (
⚠ {importError}
)}
); } /* ── Create Template Form (inline modal) ──────────────────────────── */ function CreateTemplateForm({ onClose, onSubmit, isPending, error, }: { onClose: () => void; onSubmit: (payload: CreateTemplatePayload) => void; isPending: boolean; error: string | null; }) { const [form, setForm] = useState({ mitre_technique_id: "", name: "", description: "", source: "custom", attack_procedure: "", expected_detection: "", platform: "", tool_suggested: "", severity: "", }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!form.mitre_technique_id || !form.name) return; onSubmit(form); }; return (

Create Custom Template

{/* MITRE Technique ID */}
setForm({ ...form, mitre_technique_id: e.target.value })} placeholder="e.g. T1059.001" required className="w-full rounded-lg border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-300 placeholder-gray-500 focus:border-cyan-500 focus:outline-none" />
{/* Name */}
setForm({ ...form, name: e.target.value })} placeholder="Test template name" required className="w-full rounded-lg border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-300 placeholder-gray-500 focus:border-cyan-500 focus:outline-none" />
{/* Platform */}
{/* Severity */}
{/* Description */}