feat(frontend): render markdown in description and summary fields
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
- New shared MarkdownText component (react-markdown + remark-gfm) that renders links, bold, italic, lists, code, blockquotes. External links open in a new tab with rel=noopener. - Applied to: technique description, threat actor description, test description, campaign description, detection rule descriptions, D3FEND defense descriptions, red/blue summaries and validation notes. - procedure_text (code/commands) stays in <pre> — not processed as MD. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import MarkdownText from "../components/MarkdownText";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
Loader2,
|
||||
@@ -236,7 +237,7 @@ export default function CampaignDetailPage() {
|
||||
</span>
|
||||
</div>
|
||||
{campaign.description && (
|
||||
<p className="mt-1 text-sm text-gray-400">{campaign.description}</p>
|
||||
<MarkdownText content={campaign.description} className="mt-1 text-sm text-gray-400" />
|
||||
)}
|
||||
<div className="mt-2 flex flex-wrap items-center gap-3 text-xs text-gray-500">
|
||||
{campaign.threat_actor_name && (
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import MarkdownText from "../components/MarkdownText";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
Loader2,
|
||||
@@ -182,9 +183,10 @@ export default function TechniqueDetailPage() {
|
||||
{/* Description */}
|
||||
<div className="lg:col-span-2 rounded-xl border border-gray-800 bg-gray-900 p-6">
|
||||
<h2 className="mb-3 text-lg font-semibold text-white">Description</h2>
|
||||
<p className="text-sm text-gray-400 leading-relaxed whitespace-pre-wrap">
|
||||
{technique.description || "No description available."}
|
||||
</p>
|
||||
<MarkdownText
|
||||
content={technique.description || "No description available."}
|
||||
className="text-sm text-gray-400 leading-relaxed"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Metadata */}
|
||||
@@ -579,7 +581,7 @@ function DetectionRulesSection({ rules }: { rules: DetectionRule[] }) {
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{rule.description && (
|
||||
<p className="text-xs text-gray-400 leading-relaxed">{rule.description}</p>
|
||||
<MarkdownText content={rule.description} className="text-xs text-gray-400 leading-relaxed" />
|
||||
)}
|
||||
<div className="flex flex-wrap gap-3 text-xs text-gray-500">
|
||||
{rule.rule_format && (
|
||||
@@ -702,7 +704,7 @@ function D3FENDSection({ defenses }: { defenses: Array<{
|
||||
{isExpanded && (
|
||||
<div className="mt-3 space-y-2 border-t border-gray-700/50 pt-3">
|
||||
{def.description ? (
|
||||
<p className="text-xs text-gray-300 leading-relaxed">{def.description}</p>
|
||||
<MarkdownText content={def.description} className="text-xs text-gray-300 leading-relaxed" />
|
||||
) : (
|
||||
<p className="text-xs text-gray-500 italic">No description available.</p>
|
||||
)}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import MarkdownText from "../components/MarkdownText";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { Loader2, AlertCircle, ArrowLeft } from "lucide-react";
|
||||
@@ -441,8 +442,8 @@ export default function TestDetailPage() {
|
||||
<dl className="space-y-4">
|
||||
<div>
|
||||
<dt className="text-xs font-medium uppercase text-gray-500">Description</dt>
|
||||
<dd className="mt-1 text-sm text-gray-300">
|
||||
{test.description || "\u2014"}
|
||||
<dd className="mt-1">
|
||||
<MarkdownText content={test.description || "\u2014"} className="text-sm text-gray-300" />
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import MarkdownText from "../components/MarkdownText";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import {
|
||||
Loader2,
|
||||
@@ -263,9 +264,7 @@ export default function ThreatActorDetailPage() {
|
||||
<h2 className="mb-3 text-sm font-semibold uppercase tracking-wider text-gray-500">
|
||||
Description
|
||||
</h2>
|
||||
<p className="text-sm leading-relaxed text-gray-300 whitespace-pre-line">
|
||||
{actor.description}
|
||||
</p>
|
||||
<MarkdownText content={actor.description} className="text-sm leading-relaxed text-gray-300" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user