fix(settings): give the text fields the border and padding Tailwind never supplied (#2464) - #2465
Merged
Merged
Conversation
…ever supplied
The operator-intake form (ent#463) rendered its five inputs as unpadded,
borderless bars beside the Admin sign-in email field it was meant to match.
The class string is not misspelled and nothing is missing *as Tailwind* — it
is only correct if `@tailwindcss/forms` is loaded, and this repo's
tailwind.config.js lists `typography` alone. Without those base styles
`border-gray-300` sets a COLOUR on a border whose width is 0 under preflight,
padding does not exist unless `px-3 py-2` says so, and the light background is
the UA default rather than a decision.
`SETTINGS_TEXT_INPUT_CLASS` in the existing components/settings/fieldStyles.js
states all of it explicitly, and carries NO width. That omission is load-
bearing rather than tidiness: Tailwind utilities of the same property do not
override by class-attribute order — appending `w-20` after a constant's `w-24`
is resolved by stylesheet source order, not by the array — so a width baked
into a shared shape cannot be overridden at a call site, only fought with. The
two layouts (`w-full` in a grid, `flex-1` beside a button) stay at the call
sites, which is the one thing they legitimately disagree about.
Scope, stated because it is wider than the report. Writing the guard as a rule
over every Settings field rather than over the five that were reported
immediately found FIVE MORE live instances of the identical defect that nobody
had filed: the per-user GitHub PAT field, the public-URL field, and the three
role-quota fields. Leaving them would have meant an allowlist of known-broken
fields inside the guard written to find them, which institutionalises the bug.
All ten now share one shape. The three quota fields keep `w-20 text-center`
and their native spinners — i.e. only the actual defect is fixed, not their
size or alignment, so the visual delta is exactly the missing border, padding
and light background.
Two deliberate small changes to fields that were NOT broken, both so the
shared shape stays one thing: the Admin sign-in email and public-URL inputs
gain `disabled:opacity-60 disabled:cursor-not-allowed` (matching the sibling
SETTINGS_NUMBER_INPUT_CLASS, visible only while a save is in flight) and an
explicit `bg-white` in place of the UA default.
Checkboxes and radios are deliberately outside the guard: without the forms
plugin they render as UA-native controls whose `appearance` is never reset, so
a border colour on one is inert rather than broken. Including them would have
fired on four correct controls.
Verified rather than asserted: `npm run build` and the built CSS carries
`.border`, `.px-3`, `.py-2`, `.bg-white`, `.shadow-sm` and
`.placeholder-gray-400` — the classes survive purge from a `.js` constant,
which they only do because the content globs cover `src/**/*.{vue,js,...}`.
Raw-color ratchet: no file grew; Settings.vue's gray count fell 691 -> 671.
Frontend unit suite 1536 passed.
Four mutations confirmed red then reverted: drop the bare `border` from the
constant; restore the original class string on one intake input; give the
constant a width; add the forms plugin to tailwind.config.js (which must fail,
because the constant's whole rationale is that the plugin is absent — that
assertion exists so the docstring gets re-read instead of silently becoming
wrong).
Fixes #2464
vybe
approved these changes
Sep 1, 2026
vybe
left a comment
Contributor
There was a problem hiding this comment.
Validated via /validate-pr: closing keyword ✅, shared fieldStyles constant with spec, learnings entry, build + e2e green.
vybe
pushed a commit
that referenced
this pull request
Sep 1, 2026
…end conflict) Both sides appended 2026-09-01 learnings entries; kept all three (the two #2454 entries from this branch + the #2464 Tailwind entry from dev via PR #2465). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015QWiYNh8QMuaMxcrhh2SxF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The operator-intake form (ent#463) rendered its five inputs as unpadded, borderless bars beside the Admin sign-in email field it was meant to match.
Nothing is misspelled, and nothing is missing as Tailwind. The string is only correct if
@tailwindcss/formsis loaded, and this repo'stailwind.config.jsliststypographyalone. Without those base styles:border-gray-300sets a colour on a border whose width is0under preflight — nothing renders,px-3 py-2says so,Review cannot catch this by reading: the defect is the absence of tokens nobody expects to see.
The fix
SETTINGS_TEXT_INPUT_CLASSin the existingcomponents/settings/fieldStyles.js(AC #2), stating all of it explicitly — and carrying no width.That omission is load-bearing, not tidiness: Tailwind utilities of the same property do not override by class-attribute order. Appending
w-20after a constant'sw-24is resolved by stylesheet source order, not by the array — so a width baked into a shared shape cannot be overridden at a call site, only fought with. (It is whySETTINGS_NUMBER_INPUT_CLASS, which does carryw-24, could not simply be reused here.) The two layouts —w-fullin a grid,flex-1beside a button — stay at the call sites, which is the one thing they legitimately disagree about.AC #1 holds by construction, not by comparison: the Admin sign-in email input — the field the issue names as the reference — now imports the same constant, so the two cannot drift apart again.
Scope: wider than the report, on purpose
Writing the guard as a rule over every Settings field rather than over the five that were reported immediately found five more live instances of the identical defect that nobody had filed:
UserGitHubPatPanel.vueviews/Settings.vueviews/Settings.vue×3Leaving them would have meant an allowlist of known-broken fields inside the guard written to find them — which institutionalises the bug. All ten fields now share one shape.
The three quota fields keep
w-20 text-centerand their native spinners: only the actual defect is fixed, not their size or alignment, so their visual delta is exactly the missing border, padding and light background.Two deliberate changes to fields that were not broken, so the shared shape stays one thing: the Admin sign-in email and public-URL inputs gain
disabled:opacity-60 disabled:cursor-not-allowed(matching the sibling number constant; visible only while a save is in flight) and an explicitbg-whitewhere they previously inherited the UA default.Checkboxes and radios are deliberately outside the guard — without the forms plugin they render as UA-native controls whose
appearanceis never reset, so a border colour on one is inert rather than broken. Including them fired on four correct controls; that is stated in the helper rather than left as a silent filter.Verified, not asserted
npm run build, then grepped the built CSS:.border,.px-3,.py-2,.bg-white,.shadow-sm,.placeholder-gray-400are all present. The classes survive purge from a.jsconstant, which they only do because the content globs coversrc/**/*.{vue,js,ts,jsx,tsx}— worth checking rather than assuming, since a purged constant would have shipped the same bug through the fix.Settings.vue's gray count fell 691 → 671.Guards
src/frontend/tests/unit/settingsFieldStyles.spec.js(9 tests) pins three things in order of durability:borderthat gives it a width. That is the rule; the reported five are just today's members of it. Includes a non-vacuity test so it cannot pass on a file set that no longer contains inputs.@tailwindcss/formsis still absent. If someone adds it, this fails so the constant's docstring gets re-read instead of silently becoming wrong.Four mutations confirmed red then reverted: drop the bare
border; restore the original class string on one intake input; give the constant a width; add the forms plugin.Learnings entry added for the class (a utility-class string that reads as complete while depending on a plugin the repo never loaded).
Fixes #2464