fix(admin): drop whitespace-nowrap on api-tokens date cells (5th attempt)

The /admin/api-tokens page has been painting a residual horizontal
scrollbar for four releases despite column-hide, mobile card-list, and
the admin section-strip `no-scrollbar` fixes. A fresh production probe
confirmed the actual culprit: the "Last used" and "Created" `<td>`s
carry `whitespace-nowrap`, and `formatDateTime` renders strings like
"05.05.2026, 21:46" (~110px) that exceed the 12% colgroup allotment
(~84px on a 700px content area). `whitespace-nowrap` wins over
`table-fixed`'s width contract, so the table's intrinsic width exceeds
100% and the wrapping `overflow-x-auto` paints the scrollbar.

Dropping the two `whitespace-nowrap` classes lets the date+time wrap
to two lines on narrow viewports. The card grows by one row but no
scrollbar — and at >1024px desktop the unwrapped string already fits
in the 12% allotment so the visual is unchanged for the common case.

Picked option 1 of the three W1a probe found (drop nowrap, switch to
formatDateShort, or hide "Created" at md): smallest two-line diff, no
i18n surface impact, no information loss.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.7 committed 2026-05-10 21:22:32 +02:00
1 parent a22f77881e
commit 1643a78f63
2 files changed
+43 -2

No files matched your search

@@ -122,6 +122,34 @@ describe("ApiTokenOverviewSection — responsive", () => {
expect(html).toMatch(/class="[^"]*\bp-4\b[^"]*sm:p-6/);
});
it("desktop date cells drop whitespace-nowrap (v1.4.22 C2 5th-attempt fix)", () => {
const html = render();
// The "Last used" + "Created" `<td>`s no longer carry
// `whitespace-nowrap`. The v1.4.19 production probe confirmed that
// class was the actual culprit behind the residual horizontal
// scrollbar at 768-1280px: a formatted date+time string
// ("05.05.2026, 21:46") overflowed its 12% colgroup allotment
// (~84px on a 700px content area) and won over `table-fixed`'s
// width contract, so the table's intrinsic width exceeded 100%
// and the wrapping `overflow-x-auto` painted a scrollbar. Letting
// the cell wrap to two lines costs one row of height but kills
// the bar.
const tableMatch = html.match(/<table[\s\S]*?<\/table>/);
expect(tableMatch).not.toBeNull();
const tableMarkup = tableMatch![0];
// Pick every <td> inside the desktop table that renders one of the
// two date columns (text-right + text-xs is unique to those cells)
// and assert none carries whitespace-nowrap.
const dateCellMatches =
tableMarkup.match(
/<td[^>]*\btext-right\b[^>]*\btext-xs\b[^>]*>/g,
) ?? [];
expect(dateCellMatches.length).toBeGreaterThanOrEqual(2);
for (const cell of dateCellMatches) {
expect(cell).not.toContain("whitespace-nowrap");
}
});
it("mobile timestamp lines wrap (no nowrap on the meta paragraphs)", () => {
const html = render();
const mobileMatch = html.match(/<ul[^>]*md:hidden[^>]*>([\s\S]*?)<\/ul>/);
@@ -222,12 +222,25 @@ export function ApiTokenOverviewSection() {
</Badge>
)}
</td>
<td className="text-muted-foreground px-3 py-2 text-right text-xs whitespace-nowrap">
{/* v1.4.22 C2 (5th attempt) — drop
`whitespace-nowrap` on the date cells. The
v1.4.19 A7 probe confirmed `formatDateTime`
renders "05.05.2026, 21:46" (~110px) which
exceeds the 12% `<col>` allotment (~84px on
a 700px content area); `whitespace-nowrap`
wins over `table-fixed`'s width contract,
so the table's intrinsic width exceeds 100%
and the wrapper's `overflow-x-auto` paints
the scrollbar the maintainer kept reporting
for the 5th time. Letting the date+time
wrap to two lines on narrow viewports costs
one row of height but eliminates the bar. */}
<td className="text-muted-foreground px-3 py-2 text-right text-xs">
{token.lastUsedAt
? formatDateTime(token.lastUsedAt)
: t("admin.tokenNeverUsed")}
</td>
<td className="text-muted-foreground px-3 py-2 text-right text-xs whitespace-nowrap">
<td className="text-muted-foreground px-3 py-2 text-right text-xs">
{formatDate(token.createdAt)}
</td>
</tr>