Skip to content

fix(ui): keep list query params when refreshing after a bulk edit - #17698

Open
luantaraschi wants to merge 1 commit into
payloadcms:mainfrom
luantaraschi:fix/edit-many-preserve-url-params
Open

fix(ui): keep list query params when refreshing after a bulk edit#17698
luantaraschi wants to merge 1 commit into
payloadcms:mainfrom
luantaraschi:fix/edit-many-preserve-url-params

Conversation

@luantaraschi

Copy link
Copy Markdown

Fixes #17667.

What

EditMany's success handler rebuilt the post-save URL by spreading parseSearchParams(searchParams). That value is stale in a list view, so the refresh navigated to a bare ?_r=<timestamp> and dropped columns, where, limit and sort.

Why useSearchParams() is stale here

ListQueryProvider deliberately writes the list query to the URL through the History API rather than the router, to avoid a re-render — providers/ListQuery/index.tsx#L147-L158:

// Important: do not use router.replace here to avoid re-rendering.
if (router.replaceState) {
  router.replaceState(search)
}

Anything written that way never reaches useSearchParams(). The repo already documents this exact problem and already works around it in one place — elements/Localizer/index.tsx#L63:

// can't use `useSearchParams` here because it is stale due to `window.history.pushState` in `ListQueryProvider`
const searchParams = new URLSearchParams(window.location.search)

EditMany has the same problem and was missed. This PR applies the same workaround, keeping parseSearchParams so nested params (where[or][0][and][0]…) still round-trip through qs at depth: 10.

Verified by running it

test/bulk-edit e2e against the dev server, MongoDB in Docker, CI=true (so the run gets CI's 5 retries):

Result
With the fix 1 passed
Reverting only the DrawerContent.tsx change 1 failed — and failed on all 6 attempts, so it isn't flaky

The failure message is the bug itself:

Expected substring: "limit="
Received string:    "http://localhost:3000/admin/collections/posts?_r=1786054824496&_rsc=…"

And the dev server log shows the two refresh requests side by side:

with fix:     GET /admin/collections/posts?depth=1&limit=5&_r=1786054793304  200
without fix:  GET /admin/collections/posts?_r=1786054824496                  200

A note on the test

My first attempt asserted on page.url() after the save — and it passed without the fix, which is what sent me looking. ListQueryProvider re-adds the params on the next render, so the address bar self-heals within a few hundred ms and hides the bare navigation. That matches the reporter's "depending on render timing the visible column loss either self-heals or becomes permanent."

So the test asserts on the refresh request via page.waitForRequest, which is the thing that actually goes out wrong. Flagging it because a settled-URL assertion here looks correct and silently tests nothing.

Scope

I kept this to the handler the issue reports.

What I did not verify

I did not run the full bulk-edit suite or a typecheck of the whole monorepo — only the new test, plus the control. The change is one expression inside an event handler with no type change (parseSearchParams takes a URLSearchParams either way), so I'd expect CI to be the real check on the rest.

Checklist

  • Tests added
  • Documentation — no user-facing API change

EditMany's success handler rebuilt the URL from `useSearchParams()`, which is
stale in a list view: ListQueryProvider syncs the query to the URL through the
History API to avoid a re-render, and the hook never observes that. The refresh
therefore navigated to a bare `?_r=<ts>`, dropping columns, filters and limit.

Reading the live location keeps them. The Localizer already works around the
same staleness the same way.
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.

Bulk edit (EditMany) save strips all query params from the URL — then overwrites the user's saved column preferences

1 participant