| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- //! Rendering for `sm121 report`: the Markdown table (stdout mode) and the
- //! embedded HTML page (serve mode), over the collected [`ReportRow`]s.
- use super::provenance;
- use super::{PAGE_TEMPLATE, PerfCell, ReportEntry, ReportRow};
- pub(crate) fn latest_score(r: &ReportRow) -> Option<&ReportEntry> {
- r.reports
- .iter()
- .rev()
- .find(|e| e.pct.is_some() || e.points.is_some())
- }
- pub(crate) fn latest_perf(r: &ReportRow) -> Option<(&PerfCell, Option<&PerfCell>)> {
- r.reports.iter().rev().find_map(|e| {
- let c1 = e.perf.iter().find(|p| p.d == 0 && p.c == 1);
- c1.map(|c1| (c1, e.perf.iter().find(|p| p.d == 0 && p.c == 2)))
- })
- }
- /// Normalized score, whole numbers without decimals (81, not 81.0).
- pub(crate) fn fmt_pct(pct: f64) -> String {
- if (pct - pct.trunc()).abs() < 1e-9 {
- format!("{}", pct as i64)
- } else {
- format!("{pct:.1}")
- }
- }
- pub(crate) fn fmt_tps(c: Option<&PerfCell>) -> String {
- c.map(|c| format!("{:.1}", c.tg))
- .unwrap_or_else(|| "—".into())
- }
- pub(crate) fn markdown(rows: &[ReportRow]) -> String {
- let mut s = format!(
- "# {}\n\n",
- fluent_i18n::t!("report-title", { "count" => rows.len() })
- );
- s.push_str(&format!(
- "| {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} |\n",
- t("report-col-model"),
- t("report-col-quant"),
- t("report-col-recipe"),
- t("report-col-prov"),
- t("report-col-engine"),
- t("report-col-nodes"),
- t("report-col-reports"),
- t("report-col-last"),
- t("report-col-up"),
- t("report-col-launches"),
- t("report-col-points"),
- t("report-col-score"),
- t("report-col-tps1"),
- t("report-col-tps2"),
- ));
- s.push_str("|---|---|---|---|---|---|---|---|---|---|---|---|\n");
- for r in rows {
- let last = r.reports.last();
- let latest = latest_score(r);
- let perf = latest_perf(r);
- s.push_str(&format!(
- "| {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} |\n",
- r.model,
- r.quant,
- r.name,
- provenance::cell(r),
- r.engine,
- r.nodes
- .map(|n| format!("{n}×{}", r.tp))
- .unwrap_or_else(|| format!("1×{}", r.tp)),
- r.reports.len(),
- last.map(|e| match &e.time {
- Some(t) => format!("{} {t}", e.date),
- None => e.date.clone(),
- })
- .unwrap_or("—".into()),
- r.up.map(|u| format!("● {}", crate::stamp::fmt_ts(u)))
- .unwrap_or_else(|| "—".into()),
- r.runs,
- latest
- .and_then(|e| e.points.clone())
- .unwrap_or_else(|| "—".into()),
- latest
- .and_then(|e| e.pct)
- .map(fmt_pct)
- .unwrap_or_else(|| "—".into()),
- fmt_tps(perf.map(|(a, _)| a)),
- fmt_tps(perf.and_then(|(_, b)| b)),
- ));
- }
- s
- }
- pub(crate) fn t(key: &str) -> String {
- fluent_i18n::t!(key)
- }
- /// The interactive page: template with `{{DATA}}` replaced by the JSON
- /// rows (`<` escaped so `</script>` in data can't break out).
- pub(crate) fn html_page(rows: &[ReportRow]) -> String {
- let json = serde_json::to_string(rows).unwrap_or_else(|_| "[]".into());
- PAGE_TEMPLATE.replace("{{DATA}}", &json.replace('<', "\\u003c"))
- }
- /// Same page mounted under a URL prefix — the dashboard nests it at
- /// `/recipes`, so the page's own absolute paths (its SSE stream and the
- /// `/r/<recipe>/<file>` viewer links) have to move with it.
- pub(crate) fn html_page_at(rows: &[ReportRow], prefix: &str) -> String {
- let page = html_page(rows);
- if prefix.is_empty() {
- return page;
- }
- page.replace("/events", &format!("{prefix}/events"))
- .replace("/r/", &format!("{prefix}/r/"))
- // marks the page as hosted (dashboard window): no own branding, and
- // the live chip only warns on a broken stream
- .replacen("<body>", "<body class=\"embed\">", 1)
- }
|