Tables: Back after a live filter, sort or search can show the bare table fragment instead of the page #646

Closed
opened 2026-10-01 11:50:04 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-10-01 while reviewing #313 at 0e789674a, by driving Companies in headless Chromium. It is older than #313: a click on a sort icon alone reproduces it.

After any live narrowing of a table (a search, a column filter, a sort), opening a company and pressing Back can show the table's fragment as the whole page: <html><head></head><body><div id="companies-table">…, with no title, no masthead and no styles.

Why

The list views answer an htmx request with the table fragment at the page's own address. get_template_names picks the partial when the request carries HX-Request (jobs/views.py:122-125, jobs/listing_views.py:115-118; Applications was not checked and probably shares the pattern). The response says Vary: Accept-Language, Cookie and has no Cache-Control, so the browser's HTTP cache holds the fragment under the page's address. When Back asks for that address as a document, the cache hands the fragment back.

Limits of the evidence

  • Reproduced on Companies only.
  • Playwright's Chromium has no back/forward cache. A browser that restores the page from one will not show this; a browser that goes to the HTTP cache will.

Fix

Either:

  • patch_vary_headers(response, ["HX-Request"]) on every view that answers the same address with a page or with a fragment (the three list views, and any other found with a grep for HX-Request in get_template_names), or
  • "getCacheBusterParam": true in the htmx-config meta in base.html.

The first is the correct statement of what the response depends on.

Done when

  • A test per list view shows the fragment response carries Vary: HX-Request.
  • A browser test narrows a table, opens a row and goes Back, and finds the whole page: its title, the masthead, and the narrowed table.
Found on 2026-10-01 while reviewing #313 at `0e789674a`, by driving *Companies* in headless Chromium. It is older than #313: a click on a sort icon alone reproduces it. After any live narrowing of a table (a search, a column filter, a sort), opening a company and pressing **Back** can show the table's fragment as the whole page: `<html><head></head><body><div id="companies-table">…`, with no title, no masthead and no styles. ## Why The list views answer an htmx request with the table fragment **at the page's own address**. `get_template_names` picks the partial when the request carries `HX-Request` (`jobs/views.py:122-125`, `jobs/listing_views.py:115-118`; *Applications* was not checked and probably shares the pattern). The response says `Vary: Accept-Language, Cookie` and has no `Cache-Control`, so the browser's HTTP cache holds the fragment under the page's address. When Back asks for that address as a document, the cache hands the fragment back. ## Limits of the evidence - Reproduced on *Companies* only. - Playwright's Chromium has no back/forward cache. A browser that restores the page from one will not show this; a browser that goes to the HTTP cache will. ## Fix Either: - `patch_vary_headers(response, ["HX-Request"])` on every view that answers the same address with a page or with a fragment (the three list views, and any other found with a grep for `HX-Request` in `get_template_names`), or - `"getCacheBusterParam": true` in the `htmx-config` meta in `base.html`. The first is the correct statement of what the response depends on. ## Done when - A test per list view shows the fragment response carries `Vary: HX-Request`. - A browser test narrows a table, opens a row and goes Back, and finds the whole page: its title, the masthead, and the narrowed table.
tiagoagueda added this to the 0.5.0 milestone 2026-10-01 11:50:04 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#646
No description provided.