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

The confirm page before a destructive action speaks the home page's language #9861

Merged opened this

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

Merged

scout/forge:scout/9860-the-confirm-page-before-a-destructive-ac → main 2 commits fork

  • Merged. scout/9860-the-confirm-page-before-a-destructive-ac was merged into main as 89396d6.

Review

Sign in to review this change.
3 files changed +29 −24
docs/design/areas/dialog.md +4
@@ -8,3 +8,7 @@ limb page's confirm form (`limbPreviewPage()` in `src/web/pages/limb.ts`) both d
88 - `.dialog-head` — the dialog's first row: its `h2` title (which `aria-labelledby` names) takes the width, anything beside it sits at the end.
99 - `.dialog-body` — the dialog's content, padded to the head's inset; add `.stack` when it holds several fields.
1010 - `.dialog-foot` — the dialog's actions on one row, aligned to the end, the primary or danger button last.
11
12 The confirm page before a destructive route (`confirmPage()` in `src/web/pages/search.ts`) is not a dialog: it is a page
13 heading, the one sentence of what will happen, the typed phrase when needed, and the action beside a way back, with no box
14 and no new class.
src/web/pages/search.ts +17 −24
@@ -935,30 +935,23 @@ function confirmBody(ctx: Ctx): Response {
935935
936936 const body = html`<div class="narrow-wide">
937937 ${pageHead(title)}
938 ${card(
939 html`<p>${detail}</p>
940 <form method="post" action="${to}" class="mt">
941 ${when(phrase !== "", () =>
942 formField({
943 label: `Type ${phrase} to continue`,
944 name: "confirm",
945 required: true,
946 autofocus: true,
947 mono: true,
948 autocomplete: "off",
949 }),
950 )}
951 <div class="form-actions">
952 ${btn(verb, { variant: "danger" })}
953 ${btn("Cancel", { href: back, variant: "ghost" })}
954 </div>
955 </form>`,
956 {
957 tone: "danger",
958 head: html`${icon("alert")}
959 <h2>${verb}</h2>`,
960 },
961 )}
938 <p>${detail}</p>
939 <form method="post" action="${to}" class="mt">
940 ${when(phrase !== "", () =>
941 formField({
942 label: `Type ${phrase} to continue`,
943 name: "confirm",
944 required: true,
945 autofocus: true,
946 mono: true,
947 autocomplete: "off",
948 }),
949 )}
950 <div class="form-actions">
951 ${btn(verb, { variant: "danger" })}
952 ${btn("Cancel", { href: back, variant: "ghost" })}
953 </div>
954 </form>
962955 </div>`;
963956 return page({ ctx, title: `${verb} · forge`, body });
964957 }
test/confirm-detach.test.ts +8
@@ -75,3 +75,11 @@ test("the fork's danger zone sends Detach from parent through the confirm page",
7575 expect(body).toContain("There is no undo.");
7676 expect(body).toContain(`action="${to}"`);
7777 });
78
79 test("the confirm page is a heading, a sentence and a form, not a box (#9860)", async () => {
80 const to = `/${fork.ownerName}/${fork.name}/settings/detach`;
81 const body = await (await fetch(`${servers.url}/-/confirm?to=${encodeURIComponent(to)}`, { headers: { cookie } })).text();
82 expect(body.match(/<h1[\s>]/g)?.length).toBe(1);
83 expect(body).not.toContain('class="card');
84 expect(body).toMatch(new RegExp(`<form method="post" action="${to}"`));
85 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs