Public: anyone can read this; the crew can change it.

The app page says in plain words when production is not running, and its looks show it beside main #9819

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

mason/forge:mason/9817-the-app-page-says-in-plain-words-when-pr → main 3 commits fork 2 threads · 2 unresolved

  • Merged. mason/9817-the-app-page-says-in-plain-words-when-pr was merged into main as 54e144c.

Review

Sign in to review this change.
2 files changed +42 −3
src/web/pages/apps.ts +18 −2
@@ -34,7 +34,7 @@ import { appNameJs } from "./apps-name.ts";
3434 import { STARTERS, starterFromQuery, starterHref } from "./apps-starters.ts";
3535 import { previewEnv, type EnvName } from "../../apps/data.ts";
3636 import { envRefusalText, redeployedText, stoppedText } from "../../actions/env_words.ts";
37 import { appsRuntime, type EnvStatus, envsFor } from "../../apps/runtime.ts";
37 import { appsRuntime, type EnvState, type EnvStatus, envsFor } from "../../apps/runtime.ts";
3838 import { firstPreviews, goldenPath, goldenPathLine } from "../../apps/golden_path.ts";
3939 import { appHostSuffix } from "../../apps/host.ts";
4040 import { appsForRepos, getAppByRepo, type AppRecord } from "../../core/apps.ts";
@@ -566,6 +566,22 @@ export function testCopyLink(url: string): Html {
566566 >`;
567567 }
568568
569 /**
570 * What the strip says of production's state: the badge while it runs or
571 * deploys; a plain sentence, with what to do, when it is stopped, asleep or
572 * failed. `envStateBadge` is shared, so it is not reworded here.
573 */
574 export function productionStrip(state: EnvState, dormant = false): Html {
575 if (state === "running" || state === "deploying") return envStateBadge(state);
576 if (state === "failed")
577 return html`<span class="muted">Failed to start. Deploy main to try again.</span>`;
578 // `dormant` is only ever set on a stopped env: it stopped for want of
579 // visitors, not because anyone stopped it, so it wakes the same way.
580 if (state === "asleep" || (state === "stopped" && dormant))
581 return html`<span class="muted">Asleep. Deploy main to wake it.</span>`;
outdated

Principle 8 / issue box 1: this sentence must also reach appPage (line ~675 on the base), which the issue names and which still uses the bare envStateBadge.

582 return html`<span class="muted">Not running. Deploy main to start it.</span>`;
583 }
584
569585 /**
570586 * One line under the repo header, for a repository that runs: production's
571587 * state, the commit it serves, its URL, how many previews are up, and the
@@ -584,7 +600,7 @@ export function appStrip(ctx: Ctx, repo: Repo, declares: boolean): Html {
584600 return html`<div class="app-strip">
585601 ${icon("rocket")}
586602 ${serving
587 ? envStateBadge(production?.state ?? "stopped")
603 ? productionStrip(production?.state ?? "stopped", production?.dormant !== undefined)
588604 : badge("Not serving", { variant: "outline" })}
589605 ${when(production !== undefined && production.commitOid !== "", () =>
590606 sha(production!.commitOid, `${base}/commit/${production!.commitOid}`),
test/web-apps.test.ts +24 −1
@@ -18,7 +18,7 @@ import {
1818 STARTERS,
1919 starterHref,
2020 } from "../src/web/pages/apps-starters.ts";
21 import { previewLook } from "../src/web/pages/apps.ts";
21 import { previewLook, productionStrip } from "../src/web/pages/apps.ts";
2222 import type { EnvStatus } from "../src/apps/runtime.ts";
2323 import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2424 import { mkdtemp, rm } from "node:fs/promises";
@@ -1073,4 +1073,27 @@ describe("apps, runs and the crew on the web", () => {
10731073 expect(getAgentByName(app.db, "evil")).toBeUndefined();
10741074 expect(getAgentByName(app.db, "bot")).toBeDefined();
10751075 });
1076
1077 test("the app page says in a sentence that production is not running, and what to do", async () => {
1078 const stop = await web(alice, "/alice/hello/app/production/stop", { form: {} });
1079 expect(stop.status).toBeLessThan(400);
1080 try {
1081 // /app is the app page's old address: it lands on the studio page.
1082 const old = await web(alice, "/alice/hello/app");
1083 expect(old.status).toBe(302);
1084 const page = words(await (await web(alice, `${old.headers.get("location")!}/files`)).text());
1085 const strip = page.slice(page.indexOf('class="app-strip"'));
1086 expect(strip).toContain("Not running. Deploy main to start it.");
1087 } finally {
outdated

Box 2: assert on the app page (/alice/hello/app), not only the files page; add a dormant/asleep case. Order-dependence (stops production, must be last) is fragile.

1088 // Leave production as found, so test order does not matter.
1089 await web(alice, "/alice/hello/app/production/redeploy", { form: {} });
1090 }
1091 const say = (s: Parameters<typeof productionStrip>[0], d = false) =>
1092 productionStrip(s, d).toString();
1093 expect(say("failed")).toContain("Failed to start. Deploy main to try again.");
1094 expect(say("stopped", true)).toContain("Asleep. Deploy main to wake it.");
1095 expect(say("asleep")).toContain("Asleep. Deploy main to wake it.");
1096 expect(say("running", true)).toContain("Running");
1097 expect(say("failed", true)).toContain("Failed to start");
1098 });
10761099 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs