Skip to content

fix(spa): restore detail-page stacked header reverted by #657 (#658) + 1.10.1#674

Merged
MartinCastroAlvarez merged 1 commit into
mainfrom
fix/detail-header-stacked-rows-regression
Jun 2, 2026
Merged

fix(spa): restore detail-page stacked header reverted by #657 (#658) + 1.10.1#674
MartinCastroAlvarez merged 1 commit into
mainfrom
fix/detail-header-stacked-rows-regression

Conversation

@MartinCastroAlvarez
Copy link
Copy Markdown
Owner

Summary

The detail-page header had silently regressed to the pre-#658 single-row layout. The #657 "split DetailPage/ListPage into focused modules" refactor was branched from before #658 landed, so merging it restored the old sm:flex-row sm:justify-between header — undoing the #658 fix (released as 1.8.1) without anyone noticing.

That reintroduced both bugs #658 fixed:

  1. Long single-token titles (filenames, slugs, UUIDs) collapsed to one-word-per-line at full H1 size, filling the viewport before any content showed.
  2. 8+ actions in the toolbar pushed the title clean off-screen.

Fix

Re-applies the three stacked full-width rows:

  • row 1 — breadcrumb
  • row 2 — H1 with break-words (overflow-wrap: anywhere) + text-balance
  • row 3 — toolbar (flex-wrap), with the Refresh·Edit·Delete cluster pinned to the trailing edge via ml-auto

Adds a DetailPage regression-guard test asserting the stacked layout (break-words on the title, space-y-2 on <header>, the ml-auto cluster, and the absence of sm:flex-row) so a future refactor that reverts it fails CI instead of shipping silently.

Validation

eslint (max-warnings 0) ✅, dark-mode coverage ✅, web typecheck ✅, detail vitest 11 passed + 2 new guard tests ✅. Patch release 1.10.1.

🤖 Generated with Claude Code

The #657 module-split refactor was branched from before #658 landed, so
merging it silently restored the pre-#658 single-row header (breadcrumb +
title sharing a flex row with the toolbar). That reintroduced both bugs
#658 fixed: long single-token titles collapsing to one-word-per-line at H1
size, and an 8+ action toolbar pushing the title off-screen.

Re-applies the three stacked full-width rows (breadcrumb / title with
overflow-wrap:anywhere via break-words / toolbar with Edit·Delete pinned
trailing-edge via ml-auto). Adds a DetailPage test asserting the stacked
layout (break-words, header space-y-2, ml-auto cluster, no sm:flex-row) so
a future refactor can't revert it unnoticed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@MartinCastroAlvarez MartinCastroAlvarez force-pushed the fix/detail-header-stacked-rows-regression branch from c77d6b1 to b957cb1 Compare June 2, 2026 00:16
@MartinCastroAlvarez MartinCastroAlvarez merged commit 478e0d4 into main Jun 2, 2026
6 checks passed
@MartinCastroAlvarez MartinCastroAlvarez deleted the fix/detail-header-stacked-rows-regression branch June 2, 2026 00:20
MartinCastroAlvarez added a commit that referenced this pull request Jun 2, 2026
…ed-fallback (#673) + 1.11.1 (#676)

* fix(spa): detail-header toolbar overflow — main min-w-0 + wrapping toolbar (#672)

The detail-page header already stacked breadcrumb / title / toolbar as
three full-width rows (#658/#674), but a ModelAdmin with 8+ actions still
overflowed horizontally and pushed the H1 + breadcrumb off-screen.

Root cause: the content column `<main>` is a flex item, whose default
`min-width: auto` refuses to shrink below its widest content. A toolbar
with 12+ buttons made that intrinsic width exceed the viewport, so
`flex-1` blew `main` past the viewport edge and dragged every stacked row
(title and breadcrumb included) off-screen — no header re-stacking could
help. `min-w-0` on `<main>` lets it shrink to the viewport so the
toolbar's `flex-wrap` actually reflows.

- Layout: `<main>` gets `min-w-0`.
- DetailPage toolbar row: `w-full min-w-0 flex-wrap`; Edit/Delete cluster
  stays right-aligned (`ml-auto`) on the last line regardless of action
  count.
- ObjectActionButton: long labels wrap inside the button
  (`whitespace-normal break-words`) instead of forming a wide min-content
  box.
- examples/many_actions PipelineAdmin fixture: 12 batch + 2 detail-only
  actions with long descriptions, wired into the examples settings.
- DetailPage.test.tsx: guards the wrapping/right-alignment/CSS contract
  with the 14-action fixture.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(spa): legacy-iframe refused-fallback instead of broken-image (#673) + 1.11.1

When the legacy admin refuses to be framed (Django's
XFrameOptionsMiddleware sends `X-Frame-Options: DENY`, or a cross-origin
`frame-ancestors` block), the browser painted its broken-image glyph and
no reliable `error` event fired on the iframe.

- LegacyIframe now runs a `loading → loaded → refused` state machine:
  `onLoad` marks the frame loaded; a ~4s timeout with no `onLoad` marks it
  `refused` and swaps in an explicit "Embedding refused by the legacy
  admin — open in new tab" fallback (keeps the proven-working
  Open-in-new-tab button and the #665 same-origin validation + sandbox).
- LegacyIframe.test.tsx: covers same src as the link, loaded (no flip),
  refused→fallback on timeout, no-flip-before-timeout, and off-origin
  rejection (with fake timers).
- README: documents required backend headers — `X-Frame-Options:
  SAMEORIGIN` (or removing XFrameOptionsMiddleware); cross-origin
  `Content-Security-Policy: frame-ancestors <spa-origin>` plus
  `SESSION_COOKIE_SAMESITE = "None"` + `SESSION_COOKIE_SECURE`. The
  examples/jobs `?run_custom=1` variant exercises the path end-to-end.
- Bump 1.11.0 → 1.11.1 + CHANGELOG [1.11.1] (Fixed: #672, #673).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Martin Castro Laminrs <mcastro@laminr.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants