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

Function render_html

atomic-cli/src/commands/triage/output.rs:186–297  ·  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

184/// (via [`html_escape`]); the embedded report JSON is `<`/`>`/`&`-escaped so it
185/// cannot break out of its `<script>` container.
186pub fn render_html(report: &TriageReport) -> String {
187 let verdict_class = match report.verdict {
188 Verdict::Blocked => "blocked",
189 Verdict::Stale => "stale",
190 Verdict::Ready => "ready",
191 };
192 let verdict_label = match report.verdict {
193 Verdict::Blocked => "BLOCKED",
194 Verdict::Stale => "STALE",
195 Verdict::Ready => "READY",
196 };
197 let merkle_short: String = report.inputs.view_merkle.chars().take(8).collect();
198
199 let mut h = String::new();
200 h.push_str("<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n");
201 h.push_str("<meta charset=\"utf-8\">\n");
202 h.push_str("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n");
203 h.push_str(&format!(
204 "<title>Triage {} \u{2192} {}</title>\n",
205 html_escape(&report.inputs.feature),
206 html_escape(&report.inputs.target)
207 ));
208 h.push_str("<style>\n");
209 h.push_str(HTML_STYLE);
210 h.push_str("\n</style>\n</head>\n<body>\n");
211
212 // Verdict banner.
213 h.push_str(&format!("<header class=\"banner {verdict_class}\">\n"));
214 h.push_str(&format!(
215 "<div class=\"verdict\">{}</div>\n",
216 html_escape(verdict_label)
217 ));
218 h.push_str(&format!(
219 "<div class=\"route\">{} \u{2192} {}</div>\n",
220 html_escape(&report.inputs.feature),
221 html_escape(&report.inputs.target)
222 ));
223 h.push_str(&format!(
224 "<div class=\"merkle\">merkle {}</div>\n",
225 html_escape(&merkle_short)
226 ));
227 let s = &report.summary;
228 h.push_str(&format!(
229 "<div class=\"counts\">{} changes \u{00b7} {} files \u{00b7} criteria {} met / {} unmet \u{00b7} findings {} block / {} warn / {} info</div>\n",
230 s.changes, s.files, s.criteria_met, s.criteria_unmet, s.findings_block, s.findings_warn, s.findings_info
231 ));
232 h.push_str(&format!(
233 "<div class=\"ref\">{}</div>\n",
234 html_escape(&report.reference)
235 ));
236 h.push_str("</header>\n");
237
238 // Findings.
239 h.push_str("<section id=\"findings\">\n<h2>Findings</h2>\n");
240 h.push_str("<div class=\"filters\">\n");
241 for (label, key) in [
242 ("All", "all"),
243 ("Block", "block"),

Callers 2

runMethod · 0.85

Calls 5

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

Tested by 1