feat(techniques): move legend to top with descriptions and review_required
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Replaces the minimal bottom legend with a full coverage legend panel placed above the filters. Each status shows a cell mock matching the exact colors used in the matrix, a color-coded label, and a short description of what it means. Includes review_required with its orange alert-triangle badge. Removes the old minimal bottom legend. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useState, useMemo } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Loader2, AlertCircle, Filter, X, Grid3X3, List } from "lucide-react";
|
||||
import { Loader2, AlertCircle, Filter, X, Grid3X3, List, AlertTriangle } from "lucide-react";
|
||||
import { getTechniques, type TechniqueSummary } from "../api/techniques";
|
||||
import AttackMatrix from "../components/AttackMatrix";
|
||||
import type { TechniqueStatus } from "../types/models";
|
||||
@@ -139,6 +139,72 @@ export default function TechniquesPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Legend */}
|
||||
<div className="rounded-xl border border-gray-800 bg-gray-900 p-4">
|
||||
<p className="mb-3 text-xs font-semibold uppercase tracking-wider text-gray-500">Coverage legend</p>
|
||||
<div className="flex flex-wrap gap-x-6 gap-y-3">
|
||||
|
||||
{/* Validated */}
|
||||
<div className="flex items-start gap-2.5">
|
||||
<div className="mt-0.5 h-8 w-8 shrink-0 rounded-md border border-green-500/50 bg-green-900/40" />
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-green-400">Validated</p>
|
||||
<p className="text-xs text-gray-500">Detected in ≥2 approved tests</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Partial */}
|
||||
<div className="flex items-start gap-2.5">
|
||||
<div className="mt-0.5 h-8 w-8 shrink-0 rounded-md border border-yellow-500/50 bg-yellow-900/40" />
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-yellow-400">Partial</p>
|
||||
<p className="text-xs text-gray-500">Some tests validated, coverage incomplete</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* In Progress */}
|
||||
<div className="flex items-start gap-2.5">
|
||||
<div className="mt-0.5 h-8 w-8 shrink-0 rounded-md border border-blue-500/50 bg-blue-900/40" />
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-blue-400">In Progress</p>
|
||||
<p className="text-xs text-gray-500">Tests active, awaiting validation</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Not Covered */}
|
||||
<div className="flex items-start gap-2.5">
|
||||
<div className="mt-0.5 h-8 w-8 shrink-0 rounded-md border border-red-500/50 bg-red-900/40" />
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-red-400">Not Covered</p>
|
||||
<p className="text-xs text-gray-500">Tested but not detected — confirmed gap</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Not Evaluated */}
|
||||
<div className="flex items-start gap-2.5">
|
||||
<div className="mt-0.5 h-8 w-8 shrink-0 rounded-md border border-gray-600/50 bg-gray-800/40" />
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-gray-400">Not Evaluated</p>
|
||||
<p className="text-xs text-gray-500">No tests created yet — unknown risk</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Review Required */}
|
||||
<div className="flex items-start gap-2.5">
|
||||
<div className="relative mt-0.5 h-8 w-8 shrink-0 rounded-md border border-yellow-500/50 bg-yellow-900/40">
|
||||
<div className="absolute -right-1 -top-1 rounded-full bg-orange-500 p-0.5">
|
||||
<AlertTriangle className="h-2.5 w-2.5 text-white" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-yellow-400">Review Required</p>
|
||||
<p className="text-xs text-gray-500">Pending lead validation or re-evaluation</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Filters */}
|
||||
<div className="flex flex-wrap items-center gap-4 rounded-xl border border-gray-800 bg-gray-900 p-4">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -255,28 +321,6 @@ export default function TechniquesPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Legend */}
|
||||
<div className="flex flex-wrap items-center gap-4 rounded-xl border border-gray-800 bg-gray-900 p-4">
|
||||
<span className="text-sm font-medium text-gray-400">Legend:</span>
|
||||
{STATUS_OPTIONS.filter((s) => s.value !== "all").map((status) => (
|
||||
<div key={status.value} className="flex items-center gap-2">
|
||||
<div
|
||||
className={`h-3 w-3 rounded ${
|
||||
status.value === "validated"
|
||||
? "bg-green-500"
|
||||
: status.value === "partial"
|
||||
? "bg-yellow-500"
|
||||
: status.value === "in_progress"
|
||||
? "bg-blue-500"
|
||||
: status.value === "not_covered"
|
||||
? "bg-red-500"
|
||||
: "bg-gray-600"
|
||||
}`}
|
||||
/>
|
||||
<span className="text-xs text-gray-400">{status.label}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user