Skip to content

docs(readme): honest hooks-carry-through + hardening + cross-origin sections (#623 #624 #633 #634 #635)#640

Merged
MartinCastroAlvarez merged 1 commit into
mainfrom
docs/stock-django-extension-gaps
May 31, 2026
Merged

docs(readme): honest hooks-carry-through + hardening + cross-origin sections (#623 #624 #633 #634 #635)#640
MartinCastroAlvarez merged 1 commit into
mainfrom
docs/stock-django-extension-gaps

Conversation

@MartinCastroAlvarez
Copy link
Copy Markdown
Owner

README-only — no code change, but closes the doc-only audit issues and corrects an existing misleading row in the feature table.

What's new

Verification

README-only; no code paths touched.

Side effects

The README gets longer (+118 lines), but the lines are organised under named subsections so the existing reading flow is preserved.

Closes #623, closes #624, closes #633, closes #634, closes #635.

🤖 Generated with Claude Code

…ections

Five audit findings, all README-only — no code change:

- **#623 / #624 / #625 / #626 / #627 / #628 / #630 / #622:** Add a
  "Stock-Django ModelAdmin hooks that do NOT carry through to the
  SPA" table. Documents the silent-noop hooks (template overrides,
  formfield_overrides, filter_horizontal, GFK, i18n) and the
  partially-honoured hints (raw_id_fields + radio_fields — the API
  emits the hint, the SPA still renders autocomplete / dropdown).
  Corrects the existing feature-status table where `raw_id_fields`
  was incorrectly marked ✅.
- **#633:** "Writing safe `list_display` callables" — bans the
  `mark_safe(f"...")` foot-gun + shows the `format_html`
  auto-escape equivalent. Same advice applies on legacy `/admin/`
  too, but the SPA's `dangerouslySetInnerHTML` render path makes the
  consequence visible end-to-end.
- **#634:** "Hardening" section with a worked `django-axes`
  integration pointed at the SPA's JSON login endpoint.
- **#635:** "Mounting the API on a different origin (CORS +
  cookies)" — the three-setting matrix consumers have to configure
  together (`SESSION_COOKIE_SAMESITE = None` + secure, CORS,
  CSRF_TRUSTED_ORIGINS).

Tracking issues stay open until each underlying gap closes; the
README now sets honest expectations so consumers don't ship a
release thinking these all work invisibly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@MartinCastroAlvarez MartinCastroAlvarez merged commit 949aaa9 into main May 31, 2026
5 checks passed
@MartinCastroAlvarez MartinCastroAlvarez deleted the docs/stock-django-extension-gaps branch May 31, 2026 10:23
MartinCastroAlvarez added a commit that referenced this pull request May 31, 2026
….4.13 (#643)

A ModelAdmin action that returns ``HttpResponseRedirect(some_url)``
was looking silently no-op'd to the operator: the click ran, the
toast didn't appear, and nothing visible happened. The diagnosis in
the issue blamed the API for swallowing the response, but the API
correctly extracts ``response["Location"]`` into the JSON envelope's
``redirect`` field (``api/views/actions.py:256``). The actual bug was
on the SPA: ``DetailPage`` piped the redirect URL straight into
React Router's ``navigate`` — which is scoped to the SPA's
``BrowserRouter`` ``basename``, so any URL outside the SPA mount
silently no-op'd:

  - legacy admin paths (``/admin/<app>/<model>/<pk>/change/``)
  - hijack / impersonate URLs (``/hijack/release-user/?next=…``)
  - cross-origin downloads (signed S3 URLs)

New ``followActionRedirect`` helper (`apps/web/src/action-redirect.ts`)
picks the right primitive per URL: ``navigate`` for same-origin paths
inside the SPA mount (no full reload), ``window.location.assign``
for everything else. Returns a stripped basename-relative path to
the navigate call so BrowserRouter doesn't double-prefix.

The helper is dependency-injected (``currentOrigin``,
``assignLocation``) so the test suite can lock the routing logic
without touching jsdom's non-configurable ``window.location``.

Locks: 6 new vitests in `action-redirect.test.ts` cover the SPA-
internal path, search + hash preservation, the legacy-admin path,
cross-origin URLs, the hijack pattern, and a malformed-URL fallback.

Release 1.4.13 bundles this with the unreleased changes since
1.4.12 (all already merged on main):

  - #631 / PR #641 — ``PRIMARY_COLOR`` reads ``site_primary_color``
    off the configured ``AdminSite`` before falling back to the
    setting + default.
  - #626 / PR #642 — ``raw_id_fields`` and ``radio_fields`` now
    render their intended widgets (plain-pk text input + lookup
    link, inline radio bank) instead of falling through to
    autocomplete / ``<select>``.
  - #623 / #624 / #633 / #634 / #635 — README "Stock-Django hooks
    that do NOT carry through" / "Writing safe ``list_display``
    callables" / "Hardening" / "Mounting the API on a different
    origin" sections (PR #640).
  - PR #638 — ``release.yml`` → ``publish.yml`` rename so PyPI's
    Trusted Publisher config matches the workflow filename.

Closes #620.

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