Public: anyone can read this; the crew can change it.
The flags page's form draws §5's row-fields, and .flag-form leaves the stylesheet #5184
Check · Review · Land · Live done — Landed and live in production.
mason/forge:mason/4891-the-flags-page-s-form-draws-5-s-row-fiel → main 1 commit fork
4 files
changed +18
−10
docs/DESIGN.md −1
| @@ -498,7 +498,6 @@ the same line (#4888). | ||
| 498 | 498 | - `.fg-s6` |
| 499 | 499 | - `.fg-s7` |
| 500 | 500 | - `.filters` |
| 501 | - `.flag-form` | |
| 502 | 501 | - `.front-admin` |
| 503 | 502 | - `.front-crew` |
| 504 | 503 | - `.front-featured` |
src/web/pages/flags.ts +1 −1
| @@ -88,7 +88,7 @@ export function flagsPage(ctx: Ctx): Response { | ||
| 88 | 88 | <span class="mono">${decl.default ? "on" : "off"}</span> · owner |
| 89 | 89 | ${issueLink(repo, decl.issue)} · |
| 90 | 90 | live: ${summary(v)}<br /><span class="mono">${usesLine(week, month)}</span>`, |
| 91 | trail: html`<form class="row-fields flag-form" method="post" action="/settings/flags"> | |
| 91 | trail: html`<form class="row-fields" method="post" action="/settings/flags"> | |
| 92 | 92 | <input type="hidden" name="name" value="${name}" /> |
| 93 | 93 | <select class="input" name="forge" aria-label="${name} for the forge"> |
| 94 | 94 | <option value="" ${v?.forge === undefined ? "selected" : ""}>forge: default</option> |
src/web/style/content.ts −8
| @@ -208,14 +208,6 @@ a.origin-chip:hover { border-color: var(--border-strong); color: var(--fg); } | ||
| 208 | 208 | .row:has(.headroom) { flex-wrap: wrap; } |
| 209 | 209 | .row:has(.headroom) .row-trail { flex-basis: 100%; flex-wrap: wrap; } |
| 210 | 210 | } |
| 211 | /* Settings → Flags: a flag's controls wrap under its text on a phone, never sideways. */ | |
| 212 | .flag-form { flex-wrap: wrap; justify-content: flex-end; max-width: 100%; } | |
| 213 | @media (max-width: 640px) { | |
| 214 | .row:has(.flag-form) { flex-wrap: wrap; } | |
| 215 | .row:has(.flag-form) .row-trail { flex-basis: 100%; min-width: 0; } | |
| 216 | .flag-form { justify-content: flex-start; } | |
| 217 | .flag-form .input { min-width: 0; flex: 1 1 8rem; } | |
| 218 | } | |
| 219 | 211 | .chart-box { color: var(--accent); aspect-ratio: 720 / 260; max-width: 720px; } |
| 220 | 212 | .chart-box .chart { display: block; width: 100%; height: auto; } |
| 221 | 213 | .chart-box text { fill: var(--muted-fg); font-family: var(--mono); } |
test/flags-settings.test.ts +17
| @@ -89,6 +89,23 @@ describe("settings → flags", () => { | ||
| 89 | 89 | expect(reg.flag("alpha")).toBe(false); |
| 90 | 90 | }); |
| 91 | 91 | |
| 92 | test("each flag's form is §5d's row-fields, posting its own name and fields (#4891)", async () => { | |
| 93 | const cookie = await login("alice"); | |
| 94 | const text = await (await fetch(`${servers.url}/settings/flags`, { headers: { cookie } })).text(); | |
| 95 | expect(text).not.toContain("flag-form"); | |
| 96 | const forms = text.match(/<form class="row-fields" method="post" action="\/settings\/flags">[\s\S]*?<\/form>/g) ?? []; | |
| 97 | expect(forms.length).toBe(Object.keys(reg.decls).length); | |
| 98 | const form = forms[0]!; | |
| 99 | expect(form).toContain('<input type="hidden" name="name" value="alpha" />'); | |
| 100 | for (const field of ['name="forge"', 'name="users"', 'name="roles"', 'name="percent"', 'name="clear"']) | |
| 101 | expect(form).toContain(field); | |
| 102 | ||
| 103 | expect((await post(cookie, { name: "alpha", forge: "off", percent: "5" })).status).toBe(303); | |
| 104 | expect(reg.value("alpha")).toEqual({ forge: false, percent: 5 }); | |
| 105 | await post(cookie, { name: "alpha", clear: "1" }); | |
| 106 | expect(reg.value("alpha")).toBeUndefined(); | |
| 107 | }); | |
| 108 | ||
| 92 | 109 | test("a bad value, an unknown flag and a foreign origin change nothing", async () => { |
| 93 | 110 | const cookie = await login("alice"); |
| 94 | 111 | await post(cookie, { name: "alpha", percent: "101" }); |
new above
offline