fix(frontend): render markdown descriptions properly, fix tooltip/banner wording
Aegis CI / lint-and-test (push) Has been cancelled
Snyk Security Scan / Python vulnerabilities (backend) (push) Has been cancelled
Snyk Security Scan / npm vulnerabilities (frontend) (push) Has been cancelled
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Has been cancelled
Aegis CI / lint-and-test (push) Has been cancelled
Snyk Security Scan / Python vulnerabilities (backend) (push) Has been cancelled
Snyk Security Scan / npm vulnerabilities (frontend) (push) Has been cancelled
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Has been cancelled
- Wrap 8 previously-raw description fields in MarkdownText so imported markdown (links, bold, lists, MITRE citations) renders instead of showing literal syntax: campaign cards, D3FEND countermeasure descriptions, compliance framework/control descriptions, detection rule descriptions, threat-actor and technique reference descriptions, and the RT-import preview description - Fix the "Validated" status tooltip claiming a "≥2 tests" threshold when the real rule is ≥1 validated test with full detection; reworded the adjacent "Partial" tooltip for the same clarity - Generalize the technique review_required banner text away from "MITRE ATT&CK sync" — review can also be triggered by Atomic/Caldera/ Elastic/Sigma/LOLBAS imports, intel scans, and stale-detection checks
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
||||
import { listCampaigns, createCampaign, generateCampaignFromThreatActor, type CampaignSummary } from "../api/campaigns";
|
||||
import { getThreatActors, type ThreatActorSummary } from "../api/threat-actors";
|
||||
import { useAuth } from "../context/AuthContext";
|
||||
import MarkdownText from "../components/MarkdownText";
|
||||
|
||||
const statusColors: Record<string, string> = {
|
||||
draft: "bg-gray-800/50 text-gray-400 border-gray-600/30",
|
||||
@@ -378,9 +379,10 @@ export default function CampaignsPage() {
|
||||
{campaign.name}
|
||||
</h3>
|
||||
{campaign.description && (
|
||||
<p className="mt-1 text-xs text-gray-400 line-clamp-2">
|
||||
{campaign.description}
|
||||
</p>
|
||||
<MarkdownText
|
||||
content={campaign.description}
|
||||
className="mt-1 text-xs text-gray-400 line-clamp-2"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Threat Actor */}
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
import { useAuth } from "../context/AuthContext";
|
||||
import ComplianceGauge from "../components/compliance/ComplianceGauge";
|
||||
import ControlsTable from "../components/compliance/ControlsTable";
|
||||
import MarkdownText from "../components/MarkdownText";
|
||||
|
||||
export default function CompliancePage() {
|
||||
const [selectedFrameworkId, setSelectedFrameworkId] = useState<string | null>(null);
|
||||
@@ -238,7 +239,10 @@ export default function CompliancePage() {
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-xs leading-relaxed text-gray-400">{activeFramework.description}</p>
|
||||
<MarkdownText
|
||||
content={activeFramework.description}
|
||||
className="text-xs leading-relaxed text-gray-400"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
Braces,
|
||||
} from "lucide-react";
|
||||
import { importRT, type RTImportPayload, type RTTechniqueEntry, type RTEvidenceEntry } from "../api/tests";
|
||||
import MarkdownText from "../components/MarkdownText";
|
||||
|
||||
/* ── Template JSON ─────────────────────────────────────────────────── */
|
||||
|
||||
@@ -324,7 +325,7 @@ export default function ImportRTPage() {
|
||||
<span className="text-amber-400">{preview.techniques.length} techniques</span>
|
||||
</p>
|
||||
{preview.description && (
|
||||
<p className="mt-1 text-xs text-gray-400">{preview.description}</p>
|
||||
<MarkdownText content={preview.description} className="mt-1 text-xs text-gray-400" />
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
|
||||
@@ -289,10 +289,10 @@ export default function TechniqueDetailPage() {
|
||||
<AlertTriangle className="mt-0.5 h-5 w-5 shrink-0 text-amber-400" />
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-amber-300">
|
||||
This technique has been updated in MITRE ATT&CK
|
||||
This technique needs review
|
||||
</p>
|
||||
<p className="mt-0.5 text-xs text-amber-400/70">
|
||||
The MITRE ATT&CK sync detected changes to this technique.
|
||||
New intel, detection rules, or a MITRE ATT&CK update were found for this technique.
|
||||
{technique.mitre_last_modified && (
|
||||
<> Last modified in ATT&CK: <span className="font-mono">{technique.mitre_last_modified.slice(0, 10)}</span>.</>
|
||||
)}
|
||||
@@ -694,7 +694,10 @@ export default function TechniqueDetailPage() {
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="text-sm font-medium text-gray-200">{ref.source_name}</p>
|
||||
{ref.description && (
|
||||
<p className="mt-0.5 line-clamp-2 text-xs text-gray-500">{ref.description}</p>
|
||||
<MarkdownText
|
||||
content={ref.description}
|
||||
className="mt-0.5 line-clamp-2 text-xs text-gray-500"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<a
|
||||
|
||||
@@ -617,7 +617,7 @@ export default function ThreatActorDetailPage() {
|
||||
<span className="text-gray-400">{ref.source}</span>
|
||||
)}
|
||||
{ref.description && (
|
||||
<span className="ml-2 text-gray-500">{ref.description}</span>
|
||||
<MarkdownText content={ref.description} className="ml-2 inline text-gray-500 [&_p]:inline" />
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user