Public: anyone can read this; the crew can change it.
Each line of a repository's waves list says the wave's date: `0.7.12 · 2026-10-20 · headline · 4 pulls` #6489
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/6478-each-line-of-a-repository-s-waves-list-s → main 1 commit fork
4 files
changed +33
−9
src/tui/screens/waves.ts +2 −2
| @@ -26,9 +26,9 @@ export function waveRows(entries: WaveEntry[]) { | ||
| 26 | 26 | return entries.map((e) => |
| 27 | 27 | e.ok |
| 28 | 28 | ? { |
| 29 | title: e.wave.headline, | |
| 29 | title: `${e.wave.version} · ${e.wave.date} · ${e.wave.headline}`, | |
| 30 | 30 | secondary: "", |
| 31 | meta: `${e.wave.version} ${e.wave.date}`, | |
| 31 | meta: "", | |
| 32 | 32 | } |
| 33 | 33 | : { title: e.file, secondary: `Not a wave: ${e.reason}`, meta: "" }, |
| 34 | 34 | ); |
src/web/pages/waves.ts +2 −3
| @@ -25,9 +25,9 @@ import { localScope } from "../scope.ts"; | ||
| 25 | 25 | const WHAT_A_WAVE = |
| 26 | 26 | "A wave is a release note in waves/<version>.md that names its highlights and the pulls merged since the last one."; |
| 27 | 27 | |
| 28 | /** A wave's row title: `<version> · <headline> · N pulls`, N being the pulls this viewer can see. */ | |
| 28 | /** A wave's row title: `<version> · <date> · <headline> · N pulls`, N being the pulls this viewer can see. */ | |
| 29 | 29 | export function waveLine(w: Wave, visible: number): string { |
| 30 | return `${w.version} · ${w.headline} · ${visible} ${visible === 1 ? "pull" : "pulls"}`; | |
| 30 | return `${w.version} · ${w.date} · ${w.headline} · ${visible} ${visible === 1 ? "pull" : "pulls"}`; | |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | 33 | // GET /:owner/:name/waves |
| @@ -52,7 +52,6 @@ export async function wavesPage(ctx: Ctx): Promise<Response> { | ||
| 52 | 52 | href: fileHref(e.file), |
| 53 | 53 | // The wave's own page lists these same pulls, so the two agree. |
| 54 | 54 | title: waveLine(e.wave, carriedPulls(ctx.app.db, pullRefs(e.wave), ctx.auth.user).length), |
| 55 | meta: html`${e.wave.date}`, | |
| 56 | 55 | }) |
| 57 | 56 | : row({ |
| 58 | 57 | href: fileHref(e.file), |
test/waves-line-date.test.ts added +24
| @@ -0,0 +1,24 @@ | ||
| 1 | import { expect, test } from "bun:test"; | |
| 2 | import { waveLine } from "../src/web/pages/waves.ts"; | |
| 3 | import { waveRows } from "../src/tui/screens/waves.ts"; | |
| 4 | import type { Wave } from "../src/story/wave.ts"; | |
| 5 | ||
| 6 | const wave = (version: string, date: string, headline: string): Wave => ({ | |
| 7 | version, | |
| 8 | date, | |
| 9 | headline, | |
| 10 | highlights: [], | |
| 11 | pulls: [], | |
| 12 | }); | |
| 13 | ||
| 14 | test("waveLine puts the date right after the version", () => { | |
| 15 | expect(waveLine(wave("0.7.12", "2026-10-20", "Headline"), 4)).toBe( | |
| 16 | "0.7.12 · 2026-10-20 · Headline · 4 pulls", | |
| 17 | ); | |
| 18 | expect(waveLine(wave("0.7.12", "2026-10-20", "Headline"), 1)).toContain("1 pull"); | |
| 19 | }); | |
| 20 | ||
| 21 | test("the terminal's row says the same line", () => { | |
| 22 | const rows = waveRows([{ ok: true, file: "0.7.12.md", wave: wave("0.7.12", "2026-10-20", "Headline") }]); | |
| 23 | expect(rows[0]!.title).toBe("0.7.12 · 2026-10-20 · Headline"); | |
| 24 | }); |
test/waves-page.test.ts +5 −4
| @@ -105,8 +105,9 @@ describe("waves page", () => { | ||
| 105 | 105 | expect(at("Tenth")).toBeGreaterThan(-1); |
| 106 | 106 | expect(at("Tenth")).toBeLessThan(at("Ninth")); |
| 107 | 107 | expect(at("Ninth")).toBeLessThan(at("Zeta")); |
| 108 | expect(body).toContain("0.10.0"); | |
| 109 | expect(body).toContain("2026-02-01"); | |
| 108 | expect(body).toContain("0.10.0 · 2026-02-01 · Tenth · 0 pulls"); | |
| 109 | expect(body).toContain("0.9.0 · 2026-01-01 · Ninth · 0 pulls"); | |
| 110 | expect(at("0.10.0 · 2026-02-01")).toBeLessThan(at("0.9.0 · 2026-01-01")); | |
| 110 | 111 | expect(body).toContain('href="/alice/pub/waves/0.10.0"'); |
| 111 | 112 | }); |
| 112 | 113 | |
| @@ -225,9 +226,9 @@ describe("waves page", () => { | ||
| 225 | 226 | |
| 226 | 227 | test("a row counts the pulls this viewer can see, as the wave's page lists them", async () => { |
| 227 | 228 | const body = await (await get("/alice/pub/waves")).text(); |
| 228 | expect(body).toContain("0.1.0 · Mixed · 2 pulls"); | |
| 229 | expect(body).toContain("0.1.0 · 2026-03-05 · Mixed · 2 pulls"); | |
| 229 | 230 | const guest = await (await get("/alice/pub/waves", false)).text(); |
| 230 | expect(guest).toContain("0.1.0 · Mixed · 1 pull<"); | |
| 231 | expect(guest).toContain("0.1.0 · 2026-03-05 · Mixed · 1 pull<"); | |
| 231 | 232 | expect(guest).not.toContain("2 pulls"); |
| 232 | 233 | expect(guest).not.toContain("Secret work"); |
| 233 | 234 | const page = await (await get("/alice/pub/waves/0.1.0", false)).text(); |
new above
offline