Saved views, Columns and the shape switch use the address the page loaded with, not the filtered one on screen #623

Closed
opened 2026-10-01 10:48:27 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading the Views and Columns menus and table_views, then filtering Companies live in headless Chromium and reading the menus' next fields.

Checked again on 2026-10-01 against main at 0a5cad587: still present.

The Views and Columns menus, and the Table / Board switch on Applications, carry the page's address in a hidden next field written when the page was rendered. They sit in the page header, outside the table that live filters, sorting and paging swap with hx-push-url, and nothing updates them afterwards. So after any live narrowing the address bar shows the filtered table but next still holds the address from page load. Keep this view as saves that old address as the view, and every other action in these menus sends the person back to the table as first loaded, without the filters, sort or page they had set.

  • Where:
    • templates/partials/table/views.html:41, :57 and :81: <input type="hidden" name="next" value="{{ request.get_full_path }}"> in Open as this, Forget and Keep.
    • templates/partials/table/columns.html:13: the same field in Columns (Apply, Reset and the move arrows).
    • core/views_tables.py:60-76, table_views: the saved view is urlsplit(back).query, where back is next; :88 and :40 redirect to next.
    • applications/views.py:235-241 (switch_next) and templates/applications/application_list.html:77-85: the shape switch.
    • The menus are drawn in the page header (templates/jobs/company_list.html:67-68, templates/jobs/listing_list.html:70, templates/applications/application_list.html:89-90), outside the swap targets. static/js/app.js has no code that rewrites next; the only address it reads after a swap is data-col-here, which is inside the swapped <thead>.
  • What happens: open Companies, open the Location filter and type mexico. The table narrows and the address becomes ?…location=mexico…, but every next field in the Views menu still reads /jobs/companies/ (observed). Keep the view as "In Mexico": it is stored with an empty query, the redirect shows every company, and from then on "In Mexico" opens the unfiltered table. In the same way, saving Columns, moving a column, Open as this, Forget or switching Table / Board after filtering live returns to the page as it was first loaded.
  • Why it matters: a saved view silently stores something other than what the person was looking at, which defeats #259, and the other actions throw away the person's current filters. With scripts off every filter change is a full page load, so only people with scripts on (most) meet it.
  • Fix: take next from the current address rather than from the render. Either refresh these controls on every swap (send the menus and the switch back with hx-swap-oob, as the count already is, or move them inside the swapped region), or have app.js set the next field of these forms to location.pathname + location.search on submit. The out-of-band swap keeps one source of truth on the server and needs no new script.

Done when

  • tests/e2e/test_saved_views.py types a filter into a column header before pressing Keep, and the view it then opens shows only the filtered rows. Today the test loads ?location=mexico with page.goto, so it cannot fail on this.
  • A server test in tests/test_saved_views.py asserts that an htmx response for a filtered table carries the Views and Columns next fields with the filtered query (if the out-of-band route is taken).
Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading the *Views* and *Columns* menus and `table_views`, then filtering *Companies* live in headless Chromium and reading the menus' `next` fields. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. The *Views* and *Columns* menus, and the *Table* / *Board* switch on *Applications*, carry the page's address in a hidden `next` field written when the page was rendered. They sit in the page header, outside the table that live filters, sorting and paging swap with `hx-push-url`, and nothing updates them afterwards. So after any live narrowing the address bar shows the filtered table but `next` still holds the address from page load. *Keep this view as* saves that old address as the view, and every other action in these menus sends the person back to the table as first loaded, without the filters, sort or page they had set. - **Where:** - `templates/partials/table/views.html:41`, `:57` and `:81`: `<input type="hidden" name="next" value="{{ request.get_full_path }}">` in *Open as this*, *Forget* and *Keep*. - `templates/partials/table/columns.html:13`: the same field in *Columns* (*Apply*, *Reset* and the move arrows). - `core/views_tables.py:60-76`, `table_views`: the saved view is `urlsplit(back).query`, where `back` is `next`; `:88` and `:40` redirect to `next`. - `applications/views.py:235-241` (`switch_next`) and `templates/applications/application_list.html:77-85`: the shape switch. - The menus are drawn in the page header (`templates/jobs/company_list.html:67-68`, `templates/jobs/listing_list.html:70`, `templates/applications/application_list.html:89-90`), outside the swap targets. `static/js/app.js` has no code that rewrites `next`; the only address it reads after a swap is `data-col-here`, which is inside the swapped `<thead>`. - **What happens:** open *Companies*, open the *Location* filter and type `mexico`. The table narrows and the address becomes `?…location=mexico…`, but every `next` field in the *Views* menu still reads `/jobs/companies/` (observed). Keep the view as "In Mexico": it is stored with an empty query, the redirect shows every company, and from then on "In Mexico" opens the unfiltered table. In the same way, saving *Columns*, moving a column, *Open as this*, *Forget* or switching *Table* / *Board* after filtering live returns to the page as it was first loaded. - **Why it matters:** a saved view silently stores something other than what the person was looking at, which defeats #259, and the other actions throw away the person's current filters. With scripts off every filter change is a full page load, so only people with scripts on (most) meet it. - **Fix:** take `next` from the current address rather than from the render. Either refresh these controls on every swap (send the menus and the switch back with `hx-swap-oob`, as the count already is, or move them inside the swapped region), or have `app.js` set the `next` field of these forms to `location.pathname + location.search` on submit. The out-of-band swap keeps one source of truth on the server and needs no new script. ## Done when - `tests/e2e/test_saved_views.py` types a filter into a column header before pressing *Keep*, and the view it then opens shows only the filtered rows. Today the test loads `?location=mexico` with `page.goto`, so it cannot fail on this. - A server test in `tests/test_saved_views.py` asserts that an htmx response for a filtered table carries the *Views* and *Columns* `next` fields with the filtered query (if the out-of-band route is taken).
tiagoagueda added this to the 0.5.0 milestone 2026-10-01 10:48:27 +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#623
No description provided.