MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / render_html

Function render_html

atomic-cli/src/commands/triage/output.rs:296–413  ·  view source on GitHub ↗

Render the report as ONE self-contained HTML document. No external URLs, CDNs, or scripts: all CSS is inline and the only JavaScript is a tiny vanilla filter function. Every interpolated string is HTML-escaped (via [`html_escape`]); the embedded report JSON is `<`/`>`/`&`-escaped so it cannot break out of its ` ` container.

(report: &TriageReport)

Source from the content-addressed store, hash-verified

294/// (via [`html_escape`]); the embedded report JSON is `<`/`>`/`&`-escaped so it
295/// cannot break out of its `<script>` container.
296pub fn render_html(report: &TriageReport) -> String {
297 let verdict_class = match report.verdict {
298 Verdict::Blocked => "blocked",
299 Verdict::Stale => "stale",
300 Verdict::Ready => "ready",
301 };
302 let verdict_label = match report.verdict {
303 Verdict::Blocked => "BLOCKED",
304 Verdict::Stale => "STALE",
305 Verdict::Ready => "READY",
306 };
307 let merkle_short: String = report.inputs.view_merkle.chars().take(8).collect();
308
309 let mut h = String::new();
310 h.push_str("<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n");
311 h.push_str("<meta charset=\"utf-8\">\n");
312 h.push_str("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n");
313 h.push_str(&format!(
314 "<title>Triage {} \u{2192} {}</title>\n",
315 html_escape(&report.inputs.feature),
316 html_escape(&report.inputs.target)
317 ));
318 h.push_str("<style>\n");
319 h.push_str(HTML_STYLE);
320 h.push_str("\n</style>\n</head>\n<body>\n");
321
322 // Verdict banner.
323 h.push_str(&format!("<header class=\"banner {verdict_class}\">\n"));
324 h.push_str(&format!(
325 "<div class=\"verdict\">{}</div>\n",
326 html_escape(verdict_label)
327 ));
328 h.push_str(&format!(
329 "<div class=\"route\">{} \u{2192} {}</div>\n",
330 html_escape(&report.inputs.feature),
331 html_escape(&report.inputs.target)
332 ));
333 h.push_str(&format!(
334 "<div class=\"merkle\">merkle {}</div>\n",
335 html_escape(&merkle_short)
336 ));
337 let s = &report.summary;
338 h.push_str(&format!(
339 "<div class=\"counts\">{} changes \u{00b7} {} files \u{00b7} criteria {} met / {} unmet \u{00b7} findings {} block / {} warn / {} info</div>\n",
340 s.changes, s.files, s.criteria_met, s.criteria_unmet, s.findings_block, s.findings_warn, s.findings_info
341 ));
342 h.push_str(&format!(
343 "<div class=\"ref\">{}</div>\n",
344 html_escape(&report.reference)
345 ));
346 h.push_str("</header>\n");
347
348 // Findings.
349 h.push_str("<section id=\"findings\">\n<h2>Findings</h2>\n");
350 h.push_str("<div class=\"filters\">\n");
351 for (label, key) in [
352 ("All", "all"),
353 ("Block", "block"),

Callers 3

runMethod · 0.85

Calls 6

render_finding_cardFunction · 0.85
render_walkthroughFunction · 0.85
render_intentFunction · 0.85
render_changeFunction · 0.85
escape_script_jsonFunction · 0.85
is_emptyMethod · 0.45