Public: anyone can read this; the crew can change it.
A mirror's fetch error on the repository page and the browse page's error are §5's notice, not .error-note #5088
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/5073-a-mirror-s-fetch-error-on-the-repository → main 1 commit fork 1 thread · 1 unresolved
3 files
changed +27
−2
src/web/pages/browse.ts +4 −1
| @@ -1059,7 +1059,10 @@ export function mirrorJobPage(ctx: Ctx): Response { | ||
| 1059 | 1059 | |
| 1060 | 1060 | const foot = |
| 1061 | 1061 | job.stage === "failed" |
| 1062 | ? html`<p class="error-note">${job.error ?? "The mirror failed."}</p> | |
| 1062 | ? html`<div class="toast" data-tone="danger" role="alert"> | |
| 1063 | ${icon("alert")} | |
| 1064 | <div class="toast-body">${job.error ?? "The mirror failed."}</div> | |
| 1065 | </div> | |
| 1063 | 1066 | <div class="bar mt"> |
| 1064 | 1067 | <form |
| 1065 | 1068 | method="post" |
src/web/pages/repo.ts +4 −1
| @@ -557,7 +557,10 @@ function aboutCard( | ||
| 557 | 557 | </ul> |
| 558 | 558 | ${when( |
| 559 | 559 | o.fetchError !== "", |
| 560 | () => html`<p class="error-note mt">${o.fetchError}</p>`, | |
| 560 | () => html`<div class="toast" data-tone="danger" role="status"> | |
| 561 | ${icon("alert")} | |
| 562 | <div class="toast-body">${o.fetchError}</div> | |
| 563 | </div>`, | |
| 561 | 564 | )} |
| 562 | 565 | ${when( |
| 563 | 566 | admin, |
test/origins.test.ts +19
| @@ -5,6 +5,7 @@ import { join } from "node:path"; | ||
| 5 | 5 | import { createApp, type App } from "../src/app.ts"; |
| 6 | 6 | import { serve, type Servers } from "../src/http/server.ts"; |
| 7 | 7 | import { commitToBranch, forkRepo } from "../src/actions/repos.ts"; |
| 8 | import { recordFetch } from "../src/core/origins.ts"; | |
| 8 | 9 | import { getRepo } from "../src/core/repos.ts"; |
| 9 | 10 | import { getUserByName } from "../src/core/users.ts"; |
| 10 | 11 | import { settled } from "../src/origins/jobs.ts"; |
| @@ -569,6 +570,24 @@ describe("origins: connecting, mirroring, writing through", () => { | ||
| 569 | 570 | expect(upstream?.pull?.head).toBe("loosen"); |
| 570 | 571 | }); |
| 571 | 572 | |
| 573 | test("a mirror's fetch error is drawn in the danger notice, not .error-note", async () => { | |
| 574 | const mirror = getRepo(app.db, "alice", "widgets")!; | |
| 575 | recordFetch(app.db, mirror.id, { | |
| 576 | at: "2026-01-01T00:00:00.000Z", | |
| 577 | error: "fetch failed <b>badly</b>", | |
| 578 | }); | |
| 579 | try { | |
| 580 | const text = await (await api("/alice/widgets")).text(); | |
| 581 | expect(text).toContain( | |
| 582 | '<div class="toast" data-tone="danger" role="status">', | |
| 583 | ); | |
| 584 | expect(text).toContain("fetch failed <b>badly</b>"); | |
| 585 | expect(text).not.toContain("error-note"); | |
| 586 | } finally { | |
| 587 | recordFetch(app.db, mirror.id, { at: "2026-01-01T00:00:00.000Z" }); | |
| 588 | } | |
| 589 | }); | |
| 590 | ||
| 572 | 591 | test("a fork proposing its main upstream travels under its owner's name, never onto the origin's main", async () => { |
| 573 | 592 | const alice = getUserByName(app.db, "alice")!; |
| 574 | 593 | const mirror = getRepo(app.db, "alice", "widgets")!; |
new above
offline
Lost the mt spacing the old note had; add a gap so the toast does not touch the list above. Also role=status here is right (not urgent) while browse uses alert, which is fine for a failed job.