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

After New app, land on the studio's app page — the one the studio built #161

Merged opened this

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

Merged

scout/forge:scout/151-after-new-app-land-on-the-studio-s-app-p → main 1 commit fork

  • Merged. scout/151-after-new-app-land-on-the-studio-s-app-p was merged into main as b5e32bc.

Review

Sign in to review this change.
3 files changed +41 −11
src/web/pages/apps.ts +4 −1
@@ -531,7 +531,10 @@ export async function newAppSubmit(ctx: Ctx): Promise<Response> {
531531 : plan
532532 ? ` ${plan.agent} was picked for #${issue.number} — ${plan.summary}`
533533 : ` #${issue.number} is assigned to ${issue.assigneeName}.`;
534 return flashTo(ctx, `${repoBase(repo)}/app`, { message: `${first}${second}` });
534 // The studio's app page (repoHome, once the record exists) is where this
535 // moment belongs; dev mode keeps the controls' page.
536 const target = ctx.mode === "studio" ? repoBase(repo) : `${repoBase(repo)}/app`;
537 return flashTo(ctx, target, { message: `${first}${second}` });
535538 }
536539
537540 // ---- the repo home's strip ----
test/apps.test.ts +34 −6
@@ -1280,7 +1280,7 @@ describe("New app: the form asks for the sentence, and names it (issue #60)", ()
12801280 });
12811281 expect(res.status).toBe(303);
12821282 expect(res.headers.get("location")).toBe(
1283 "/nadia/keep-a-shared-grocery-list/app",
1283 "/nadia/keep-a-shared-grocery-list",
12841284 );
12851285 });
12861286
@@ -1290,7 +1290,7 @@ describe("New app: the form asks for the sentence, and names it (issue #60)", ()
12901290 });
12911291 expect(res.status).toBe(303);
12921292 expect(res.headers.get("location")).toBe(
1293 "/nadia/keep-a-shared-grocery-list-2/app",
1293 "/nadia/keep-a-shared-grocery-list-2",
12941294 );
12951295 });
12961296
@@ -1308,7 +1308,7 @@ describe("New app: the form asks for the sentence, and names it (issue #60)", ()
13081308 description: "Keep a shared grocery list",
13091309 });
13101310 expect(res.status).toBe(303);
1311 expect(res.headers.get("location")).toBe("/nadia/groceries/app");
1311 expect(res.headers.get("location")).toBe("/nadia/groceries");
13121312 });
13131313 });
13141314
@@ -1367,7 +1367,7 @@ describe("New app lands on the app's page, not the flash (issue #133)", () => {
13671367 await rm(dataDir, { recursive: true, force: true });
13681368 });
13691369
1370 test("POST /apps/new redirects to the app's page, which shows the name, the URL and the first issue", async () => {
1370 test("in studio mode, POST /apps/new redirects to the studio's app page, which shows the name, the URL and the first issue", async () => {
13711371 const submitted = await fetch(`${base}/apps/new`, {
13721372 method: "POST",
13731373 headers: { cookie, origin: base },
@@ -1381,7 +1381,7 @@ describe("New app lands on the app's page, not the flash (issue #133)", () => {
13811381 redirect: "manual",
13821382 });
13831383 expect(submitted.status).toBe(303);
1384 expect(submitted.headers.get("location")).toBe("/priya/planner/app");
1384 expect(submitted.headers.get("location")).toBe("/priya/planner");
13851385 const flash = (submitted.headers.get("set-cookie") ?? "").split(";")[0]!;
13861386 expect(flash).toStartWith("forge_flash=");
13871387
@@ -1391,7 +1391,35 @@ describe("New app lands on the app's page, not the flash (issue #133)", () => {
13911391 expect(landed.status).toBe(200);
13921392 const html = await landed.text();
13931393 expect(html).toContain("planner");
1394 expect(html).toContain(`http://planner.${DOMAIN}:${servers.port}`);
1394 expect(html).toContain(`planner.${DOMAIN}:${servers.port}`);
1395 expect(html).toContain("#1 is assigned to bot.");
1396 });
1397
1398 test("in dev mode, POST /apps/new redirects to dev's app page, chosen from ctx.mode", async () => {
1399 const submitted = await fetch(`${base}/apps/new`, {
1400 method: "POST",
1401 headers: { cookie: `${cookie}; forge_mode=dev`, origin: base },
1402 body: new URLSearchParams({
1403 owner: "priya",
1404 name: "tracker",
1405 description: "Track expenses",
1406 visibility: "private",
1407 agent: "bot",
1408 }),
1409 redirect: "manual",
1410 });
1411 expect(submitted.status).toBe(303);
1412 expect(submitted.headers.get("location")).toBe("/priya/tracker/app");
1413 const flash = (submitted.headers.get("set-cookie") ?? "").split(";")[0]!;
1414 expect(flash).toStartWith("forge_flash=");
1415
1416 const landed = await fetch(`${base}${submitted.headers.get("location")}`, {
1417 headers: { cookie: `${cookie}; forge_mode=dev; ${flash}` },
1418 });
1419 expect(landed.status).toBe(200);
1420 const html = await landed.text();
1421 expect(html).toContain("tracker");
1422 expect(html).toContain(`http://tracker.${DOMAIN}:${servers.port}`);
13951423 expect(html).toContain("#1 is assigned to bot.");
13961424 });
13971425
test/web-apps.test.ts +3 −4
@@ -164,7 +164,7 @@ describe("apps, runs and the crew on the web", () => {
164164 },
165165 });
166166 expect(created.status).toBe(303);
167 expect(created.headers.get("location")).toBe("/alice/hello/app");
167 expect(created.headers.get("location")).toBe("/alice/hello");
168168 expect(flashOf(created)).toContain(
169169 `hello is starting at http://hello.${DOMAIN}:${servers.port}`,
170170 );
@@ -172,11 +172,10 @@ describe("apps, runs and the crew on the web", () => {
172172 expect(hello).toBeDefined();
173173 expect(getAppByRepo(app.db, hello.id)?.slug).toBe("hello");
174174
175 // The repo home wears the strip and the App tab.
175 // The studio's app page — the repo home for a repository that is an
176 // app — carries the same URL, in a link to open it.
176177 const home = await bodyOf(alice, "/alice/hello");
177 expect(home).toContain('class="app-strip"');
178178 expect(home).toContain('href="/alice/hello/app/production/open"');
179 expect(home).toContain('href="/alice/hello/app"');
180179 // A plain repository wears neither.
181180 const plain = await web(alice, "/new", {
182181 form: { owner: "alice", name: "plain", visibility: "private" },

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs