Public: anyone can read this; the crew can change it.
The forge toolbar names the environment in one word (production, preview of pull N) and links to the pull #11438
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/11434-the-forge-toolbar-names-the-environment → main 3 commits fork 1 thread · 1 unresolved
6 files
changed +19
−15
src/apps/toolbar.ts +3 −3
| @@ -86,7 +86,7 @@ const toolbarSource = `(function () { | ||
| 86 | 86 | panel.appendChild(el); |
| 87 | 87 | } |
| 88 | 88 | if (d.app) line(d.app, true); |
| 89 | if (d.env === "production") line("Production"); | |
| 89 | if (d.env === "production") line("production"); | |
| 90 | 90 | var LS = "color:#8ab4ff;text-decoration:none;display:flex;align-items:center;min-height:44px"; |
| 91 | 91 | var pullHref = ""; |
| 92 | 92 | // The pull this preview shows, one tap away: built from the script's own origin, never from page text. |
| @@ -96,12 +96,12 @@ const toolbarSource = `(function () { | ||
| 96 | 96 | if (d.env === "production") {} |
| 97 | 97 | else if (pullHref) { |
| 98 | 98 | var pl = document.createElement("a"); |
| 99 | pl.textContent = "Preview of pull #" + d.pull; | |
| 99 | pl.textContent = "preview \\u00b7 #" + d.pull; | |
| 100 | 100 | pl.href = pullHref; |
| 101 | 101 | pl.rel = "noopener"; |
| 102 | 102 | pl.style.cssText = LS; |
| 103 | 103 | panel.appendChild(pl); |
| 104 | } else if (d.pull) line("Preview of pull #" + d.pull); | |
| 104 | } else if (d.pull) line("preview \\u00b7 #" + d.pull); | |
| 105 | 105 | if (d.title) line(d.title); |
| 106 | 106 | var CW = ${JSON.stringify(CHECK_WORDS)}; |
| 107 | 107 | if (d.env !== "production" && d.check && Object.prototype.hasOwnProperty.call(CW, d.check)) line(CW[d.check]); |
test/apps-pill-check.test.ts +1 −1
| @@ -92,7 +92,7 @@ describe("the pill's check line", () => { | ||
| 92 | 92 | // Production, even handed a check, names the app and says no check. |
| 93 | 93 | const prod = drawn({ app: "notes", env: "production", check: "passed" }); |
| 94 | 94 | expect(prod).toContain("notes"); |
| 95 | expect(prod).toContain("Production"); | |
| 95 | expect(prod).toContain("production"); | |
| 96 | 96 | expect(prod.some((t) => /^(Checks|No checks)/.test(t))).toBe(false); |
| 97 | 97 | }); |
| 98 | 98 |
test/apps-pill-freshness.test.ts +3 −3
| @@ -269,14 +269,14 @@ describe("the pill's script draws the freshness line", () => { | ||
| 269 | 269 | ]; |
| 270 | 270 | for (const [extra, said] of cases) { |
| 271 | 271 | const lines = panelLines({ ...base, ...extra }); |
| 272 | expect(lines.slice(0, 4)).toEqual(["site", "Preview of pull #7", "Add a thing", said]); | |
| 272 | expect(lines.slice(0, 4)).toEqual(["site", "preview \u00b7 #7", "Add a thing", said]); | |
| 273 | 273 | expect(lines.filter((l) => words.includes(l as never))).toEqual([said]); |
| 274 | 274 | } |
| 275 | 275 | }); |
| 276 | 276 | |
| 277 | 277 | test("the line follows the pull when there is no title", () => { |
| 278 | 278 | const lines = panelLines({ ...base, title: "", state: "merged" }); |
| 279 | expect(lines.slice(0, 3)).toEqual(["site", "Preview of pull #7", FRESHNESS_WORDS.merged]); | |
| 279 | expect(lines.slice(0, 3)).toEqual(["site", "preview \u00b7 #7", FRESHNESS_WORDS.merged]); | |
| 280 | 280 | }); |
| 281 | 281 | |
| 282 | 282 | test("merged and closed win over deploying and behind; deploying wins over behind", () => { |
| @@ -290,7 +290,7 @@ describe("the pill's script draws the freshness line", () => { | ||
| 290 | 290 | expect(panelLines({ ...base, state: "open" }).filter((l) => words.includes(l as never))).toEqual([]); |
| 291 | 291 | expect(panelLines({ ...base }).filter((l) => words.includes(l as never))).toEqual([]); |
| 292 | 292 | const prod = panelLines({ app: "site", repo: "alice/site", env: "production" }); |
| 293 | expect(prod.slice(0, 2)).toEqual(["site", "Production"]); | |
| 293 | expect(prod.slice(0, 2)).toEqual(["site", "production"]); | |
| 294 | 294 | expect(prod.filter((l) => words.includes(l as never))).toEqual([]); |
| 295 | 295 | }); |
| 296 | 296 | }); |
test/apps-toolbar.test.ts +7 −3
| @@ -476,15 +476,19 @@ describe("the pill's keyboard and touch behaviour", () => { | ||
| 476 | 476 | |
| 477 | 477 | |
| 478 | 478 | test("on a preview with a repo the pull line links to the pull; otherwise it is plain text", () => { |
| 479 | const a = tree({ app: "notes", repo: "alice/notes", pull: "12" }).lines.find((l) => l.textContent === "Preview of pull #12")!; | |
| 479 | const a = tree({ app: "notes", repo: "alice/notes", pull: "12" }).lines.find((l) => l.textContent === "preview \u00b7 #12")!; | |
| 480 | 480 | expect(a.tag).toBe("a"); |
| 481 | 481 | expect(a.href).toBe("https://forge.test/alice/notes/pulls/12"); |
| 482 | 482 | expect(a.style.cssText).toContain("min-height:44px"); |
| 483 | 483 | const prod = tree({ app: "notes", repo: "alice/notes", env: "production", pull: "12" }); |
| 484 | expect(prod.lines.some((l) => l.textContent.includes("Preview"))).toBe(false); | |
| 484 | expect(prod.lines.some((l) => l.textContent.startsWith("preview \u00b7"))).toBe(false); | |
| 485 | expect(prod.lines.some((l) => l.textContent === "production")).toBe(true); | |
| 486 | // An unknown environment with no pull draws no environment line at all. | |
| 487 | const unknown = tree({ app: "notes", repo: "alice/notes", env: "staging" }); | |
| 488 | expect(unknown.lines.some((l) => l.textContent === "production" || l.textContent.startsWith("preview"))).toBe(false); | |
| 485 | 489 | for (const bad of [{ pull: "12x" }, { pull: "../1" }, { pull: "1234567890" }, { repo: "" }]) { |
| 486 | 490 | const t = tree({ app: "notes", repo: "alice/notes", pull: "12", ...bad }); |
| 487 | const l = t.lines.find((x) => x.textContent.startsWith("Preview of pull"))!; | |
| 491 | const l = t.lines.find((x) => x.textContent.startsWith("preview \u00b7"))!; | |
| 488 | 492 | expect(l.tag === "a").toBe(false); |
| 489 | 493 | } |
| 490 | 494 | }); |
test/lost-journey.test.ts +4 −4
| @@ -229,7 +229,7 @@ describe("lost journey: where you are and three exits", () => { | ||
| 229 | 229 | expect(focusable(home)).toBe(true); |
| 230 | 230 | expect(home.href).toBe(`${origin}/`); |
| 231 | 231 | |
| 232 | const pullLink = run.named(`Preview of pull #${pull}`)!; | |
| 232 | const pullLink = run.named(`preview \u00b7 #${pull}`)!; | |
| 233 | 233 | expect(focusable(pullLink)).toBe(true); |
| 234 | 234 | expect(pullLink.href).toBe(`${origin}/alice/public/pulls/${pull}`); |
| 235 | 235 | |
| @@ -258,8 +258,8 @@ describe("lost journey: where you are and three exits", () => { | ||
| 258 | 258 | const cookie = cookieFor("public", "production"); |
| 259 | 259 | const html = await (await ask(host, "/", cookie)).text(); |
| 260 | 260 | const run = await boot(html, await crewOf(host, cookie), `http://${host}/`); |
| 261 | expect(run.named("Production")).toBeDefined(); | |
| 262 | expect(run.built.some((e) => String(e.textContent).startsWith("Preview of pull"))).toBe(false); | |
| 261 | expect(run.named("production")).toBeDefined(); | |
| 262 | expect(run.built.some((e) => String(e.textContent).startsWith("preview \u00b7"))).toBe(false); | |
| 263 | 263 | expect(run.named("Home")!.href).toBe(`${new URL(servers.url).origin}/`); |
| 264 | 264 | }); |
| 265 | 265 | |
| @@ -272,7 +272,7 @@ describe("lost journey: where you are and three exits", () => { | ||
| 272 | 272 | expect(tag[2]).toContain(` data-env="pull-${pull}"`); |
| 273 | 273 | expect(tag[2]).toContain(` data-pull="${pull}"`); |
| 274 | 274 | const run = await boot(html, await crewOf(host), `http://${host}/`); |
| 275 | expect(run.named(`Preview of pull #${pull}`)!.href).toBe(`${new URL(servers.url).origin}/alice/public/pulls/${pull}`); | |
| 275 | expect(run.named(`preview \u00b7 #${pull}`)!.href).toBe(`${new URL(servers.url).origin}/alice/public/pulls/${pull}`); | |
| 276 | 276 | expect(run.named("Home")).toBeDefined(); |
| 277 | 277 | expect(run.named("Tell the crew")).toBeUndefined(); |
| 278 | 278 | // Comment goes to the forge's own page, which asks the stranger to sign in there. |
test/toolbar-injection.test.ts +1 −1
| @@ -85,6 +85,6 @@ test("the pill overlays the page: fixed, out of flow, in a shadow root", () => { | ||
| 85 | 85 | }); |
| 86 | 86 | |
| 87 | 87 | test("on a preview the pill links to the pull's forge page in plain words", () => { |
| 88 | expect(toolbarJs).toContain('"Preview of pull #"'); | |
| 88 | expect(toolbarJs).toContain('"preview \\u00b7 #"'); | |
| 89 | 89 | expect(toolbarJs).toContain('"/pulls/"'); |
| 90 | 90 | }); |
Now vacuous: the drawn text is lowercase "preview", so includes("Preview") is always false. Assert on "preview \u00b7" so this fails if production draws the pull line.