From 10ec0ec8d42f344911b5849a2306431469d314b2 Mon Sep 17 00:00:00 2001 From: Stuart Date: Sun, 26 Jul 2026 11:42:47 +1000 Subject: [PATCH] fix: handle mobile results and review fallbacks --- index.html | 6 ++++++ src/resultsLayout.test.js | 12 ++++++++++++ src/reviewPresentation.js | 18 ++++++++++-------- src/reviewPresentation.test.js | 27 +++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 src/resultsLayout.test.js diff --git a/index.html b/index.html index 3a5eacb..aa0f5e5 100644 --- a/index.html +++ b/index.html @@ -1429,6 +1429,12 @@ body.results-fullscreen .results-header-left h2 { font-size: 22px; } body.results-fullscreen .results-action-bar { grid-template-columns: 1fr; } } + @media (max-width: 768px) { + body.results-fullscreen .sidebar, + body.results-fullscreen.results-with-sidebar .sidebar { + display: none; + } + } @media (prefers-reduced-motion: reduce) { .results-view *, .results-view *::before, diff --git a/src/resultsLayout.test.js b/src/resultsLayout.test.js new file mode 100644 index 0000000..a5b0ca5 --- /dev/null +++ b/src/resultsLayout.test.js @@ -0,0 +1,12 @@ +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import test from "node:test"; + +const html = readFileSync(new URL("../index.html", import.meta.url), "utf8"); + +test("hides the prompt sidebar above mobile Results", () => { + assert.match( + html, + /@media \(max-width: 768px\)[\s\S]*?body\.results-fullscreen \.sidebar,[\s\S]*?body\.results-fullscreen\.results-with-sidebar \.sidebar \{\s*display: none;/, + ); +}); diff --git a/src/reviewPresentation.js b/src/reviewPresentation.js index ec645ab..992b224 100644 --- a/src/reviewPresentation.js +++ b/src/reviewPresentation.js @@ -262,14 +262,16 @@ export function buildReviewPresentation({ bundle, reviewResult }) { const safeBundle = toObject(bundle); const artifacts = asArray(safeBundle.artifacts); const { root, rawText } = unwrapReviewPayload(reviewResult); - const overallReview = toObject( - root.bundleReview - || root.overallReview - || root.overall - || root.bundleSummary - || root.summaryReview - || root.review, - ); + const overallReview = [ + root.bundleReview, + root.overallReview, + root.overall, + root.bundleSummary, + root.summaryReview, + root.review, + ] + .map(toObject) + .find((candidate) => Object.keys(candidate).length) || {}; const reviewArtifacts = asArray(root.artifacts || root.files || root.reviews); const artifactPresentations = artifacts.map((artifact, index) => ( buildArtifactPresentation(safeBundle, reviewArtifacts, artifact, index) diff --git a/src/reviewPresentation.test.js b/src/reviewPresentation.test.js index 801eaac..cea0c3d 100644 --- a/src/reviewPresentation.test.js +++ b/src/reviewPresentation.test.js @@ -211,3 +211,30 @@ test("preserves top-level artifact reviews alongside bundleReview", () => { assert.equal(presentation.reviewCoverage.reviewed, 2); assert.equal(presentation.artifacts[0].findings[0].severity, "pass"); }); + +test("falls back from malformed bundleReview to a valid overallReview", () => { + for (const bundleReview of [{}, "not a review object"]) { + const presentation = buildReviewPresentation({ + bundle, + reviewResult: { + bundleReview, + overallReview: { + status: "pass", + score: 94, + summary: "The valid overall review was preserved.", + findings: [ + { + severity: "info", + message: "The bundle structure is valid.", + }, + ], + }, + artifacts: [], + }, + }); + + assert.equal(presentation.score, 94); + assert.equal(presentation.summary, "The valid overall review was preserved."); + assert.equal(presentation.findings[0].message, "The bundle structure is valid."); + } +});