From 679ab384246a55daddf60d0c37fb02fbf0f9378c Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 10 Sep 2026 01:38:41 +0200 Subject: [PATCH] Say the right thing beside a case that did not run A blocked case was showing the last claim it managed to check -- 'and the app knows it is a child profile' -- rather than the reason it stopped, which is the one thing the card exists to tell the owner. The message now follows the outcome: a blocked case is asking him for something, so it shows the request; a failed one is asking about the app, so it shows the claim that did not hold. Screenshots also needed a file token. e2e_runs is superuser-only, which makes its files protected, and an tag sends no Authorization header -- so without one every picture on the page is a broken icon. Co-Authored-By: Claude Opus 5 --- pb_public/status.html | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/pb_public/status.html b/pb_public/status.html index 4ff61c6..78b5238 100644 --- a/pb_public/status.html +++ b/pb_public/status.html @@ -715,12 +715,22 @@ function normName(s){ return String(s).toLowerCase().replace(/\.[a-z0-9]+$/, "").replace(/[^a-z0-9]+/g, "_"); } +// A short-lived token for the protected files, fetched once per render. +// +// `e2e_runs` is superuser-only, which makes its files protected, which means an +// tag cannot fetch one on the strength of the page's own session -- the +// browser sends no Authorization header with an image request. Without this +// every screenshot on the page is a broken icon. +var fileTok = ""; + function shotUrl(r, caseId, shotName){ var want = normName(caseId + "_" + shotName); var hit = (r.shots || []).filter(function(f){ return normName(f).indexOf(want) === 0; })[0]; - return hit ? "/api/files/e2e_runs/" + r.id + "/" + hit : null; + if (!hit) return null; + return "/api/files/e2e_runs/" + r.id + "/" + hit + + (fileTok ? "?token=" + encodeURIComponent(fileTok) : ""); } function caseRow(r, c){ @@ -730,10 +740,17 @@ function caseRow(r, c){ return u ? '
' + esc(s.name) + "
" : ""; }).join(""); + // What to say beside the id, in the order that answers the question the + // outcome raises. A blocked case is asking the owner for something, so its + // message is that request; a failed one is asking about the app, so it is the + // claim that did not hold. Reading the last claim for everything showed a + // blocked case saying "and the app knows it is a child profile", which is the + // last thing it managed to check and not the reason it stopped. var checks = (c.evidence || []).filter(function(e){ return e.kind === "checked"; }); - var claim = checks.length - ? checks[checks.length - 1].claim - : (c.needs || c.error || ""); + var broke = checks.filter(function(e){ return e.ok === false; })[0]; + var claim = c.outcome === "blocked" ? (c.needs || "") + : c.outcome === "fail" ? ((broke && broke.claim) || c.error || "") + : (checks.length ? checks[checks.length - 1].claim : ""); return '
' + outcomePill(c.outcome) + '' + esc(c.id) + "" + (c.blocker ? 'blokuje' : "") + @@ -1351,6 +1368,11 @@ async function load(){ if (prefs.view === "e2e") { var rs = await records("e2e_runs", { sort: "-created", perPage: 40 }) .catch(function(){ return { items: [] }; }); + fileTok = ""; + try { + var ft = await api("/api/files/token", { method: "POST" }); + fileTok = ft.token || ""; + } catch (_) { /* the cards still render; the pictures will not */ } el("main").innerHTML = viewE2e(rs.items || []); wire(); return;