Public: anyone can read this; the crew can change it.
A frozen mirror's notice and reconnect form draw §5's card, row and btn, and .frozen, .frozen-form, .frozen-sentence leave the markup #4187
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/4128-a-frozen-mirror-s-notice-and-reconnect-f → main 1 commit fork
2 files
changed +34
−15
src/web/pages/frozen.ts +22 −15
| @@ -82,21 +82,27 @@ export function frozenBlock(ctx: Ctx, repo: Repo): Html | null { | ||
| 82 | 82 | // is filled with something discovery takes as it is. |
| 83 | 83 | const forge = URL.parse(d.htmlUrl)?.origin ?? ""; |
| 84 | 84 | const connect = `/settings/origins${forge === "" ? "" : `?host=${encodeURIComponent(forge)}`}#connect`; |
| 85 | const row = (body: Html): Html => | |
| 86 | html`<li class="row"><div class="row-main">${body}</div></li>`; | |
| 85 | 87 | const action = !admin |
| 86 | ? html`<p class="muted small mt"> | |
| 87 | An admin of this repository can reconnect it. | |
| 88 | </p>` | |
| 88 | ? row( | |
| 89 | html`<p class="muted small"> | |
| 90 | An admin of this repository can reconnect it. | |
| 91 | </p>`, | |
| 92 | ) | |
| 89 | 93 | : origins.length === 0 |
| 90 | ? html`<p class="small mt"> | |
| 91 | Connect an | |
| 92 | account${host === "" ? null : html` at ${hostLabel(d.htmlUrl)}`} under | |
| 93 | <a href="${connect}">Settings → Origins</a>: connecting one reconnects | |
| 94 | this mirror by itself. | |
| 95 | </p>` | |
| 96 | : html`<form | |
| 94 | ? row( | |
| 95 | html`<p class="small"> | |
| 96 | Connect an | |
| 97 | account${host === "" ? null : html` at ${hostLabel(d.htmlUrl)}`} | |
| 98 | under <a href="${connect}">Settings → Origins</a>: connecting one | |
| 99 | reconnects this mirror by itself. | |
| 100 | </p>`, | |
| 101 | ) | |
| 102 | : row(html`<form | |
| 97 | 103 | method="post" |
| 98 | 104 | action="${repoBase(repo)}/settings/origin/reconnect" |
| 99 | class="frozen-form" | |
| 105 | class="field-row" | |
| 100 | 106 | > |
| 101 | 107 | ${selectField({ |
| 102 | 108 | name: "origin", |
| @@ -108,11 +114,12 @@ export function frozenBlock(ctx: Ctx, repo: Repo): Html | null { | ||
| 108 | 114 | })), |
| 109 | 115 | })} |
| 110 | 116 | ${btn("Reconnect", { size: "sm", variant: "primary", icon: "sync" })} |
| 111 | </form>`; | |
| 117 | </form>`); | |
| 112 | 118 | return card( |
| 113 | html`<p class="frozen-sentence">${frozenSentence(d)}</p> | |
| 114 | ${action}`, | |
| 115 | { tone: "attn", id: "frozen", extra: "frozen" }, | |
| 119 | html`<ul class="list"> | |
| 120 | ${row(html`<p>${frozenSentence(d)}</p>`)} ${action} | |
| 121 | </ul>`, | |
| 122 | { tone: "attn", id: "frozen", pad: false }, | |
| 116 | 123 | ); |
| 117 | 124 | } |
| 118 | 125 |
test/origins-reconnect.test.ts +12
| @@ -366,6 +366,7 @@ describe("a frozen mirror is said, and reconnected in one click", () => { | ||
| 366 | 366 | for (const path of ["/alice/widgets", "/alice/widgets/branches"]) { |
| 367 | 367 | const page = await words(await api(path)); |
| 368 | 368 | expect(page).toContain('id="frozen"'); |
| 369 | expect(page).not.toMatch(/class="[^"]*\bfrozen(-form|-sentence)?\b/); | |
| 369 | 370 | expect(page).toContain("octo/widgets"); |
| 370 | 371 | expect(page).toContain( |
| 371 | 372 | `but that origin was disconnected on <time datetime="`, |
| @@ -629,6 +630,17 @@ describe("a frozen mirror is said, and reconnected in one click", () => { | ||
| 629 | 630 | expect((await repoJson()).origin?.detached).toBe(true); |
| 630 | 631 | const again = originRow(octo, octo.url); |
| 631 | 632 | tip = await advanceUpstream("page.txt"); |
| 633 | const offered = await api("/alice/widgets").then((r) => r.text()); | |
| 634 | expect(offered).toContain("it has been frozen since"); | |
| 635 | expect(offered).toContain( | |
| 636 | 'action="/alice/widgets/settings/origin/reconnect"', | |
| 637 | ); | |
| 638 | expect(offered).toContain('name="origin"'); | |
| 639 | expect(offered).toContain(`value="${again}"`); | |
| 640 | expect(offered).toContain("Reconnect through"); | |
| 641 | expect(await words(await api("/alice/widgets"))).toContain("Reconnect"); | |
| 642 | for (const old of ["frozen-form", "frozen-sentence", 'class="card frozen']) | |
| 643 | expect(offered).not.toContain(old); | |
| 632 | 644 | const viaPage = await api("/alice/widgets/settings/origin/reconnect", { |
| 633 | 645 | method: "POST", |
| 634 | 646 | headers: { "content-type": "application/x-www-form-urlencoded" }, |
new above
offline