Skip to content

fix(dashboard): Forward transformQueryKey and view options from ListPage - #5066

Merged
biggamesmallworld merged 4 commits into
vendurehq:masterfrom
grolmus:mgrolmus/oss-656-listpage-does-not-forward-transformquerykey-to
Aug 4, 2026
Merged

fix(dashboard): Forward transformQueryKey and view options from ListPage#5066
biggamesmallworld merged 4 commits into
vendurehq:masterfrom
grolmus:mgrolmus/oss-656-listpage-does-not-forward-transformquerykey-to

Conversation

@grolmus

@grolmus grolmus commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

ListPage now forwards transformQueryKey, disableViewOptions and includeSelectionColumn to the underlying PaginatedListDataTable, so pages built on ListPage can actually use them.

Root cause

ListPage builds a commonTableProps object and spreads it into PaginatedListDataTable, forwarding most props — but three real PaginatedListDataTable props were missing from that object: transformQueryKey, disableViewOptions and includeSelectionColumn.

The harmful one is transformQueryKey. The default react-query key only reflects page, itemsPerPage, sorting, the column filters and the debounced search term. Any state a page injects through transformVariables (a language selector, an action-bar status filter, a parent entity id) is invisible to the cache key. Without a way to also transform the key, the list fetches once and then serves that first response for every value of the injected state — no error, no empty table, the rows simply never change. disableViewOptions / includeSelectionColumn were missing the same way but fail visibly.

Change

Add the three props in list-page.tsx in the three places a forwarded prop must appear: the ListPageProps interface (with JSDoc), the component destructuring, and the commonTableProps object literal. Types mirror PaginatedListDataTable exactly. No behaviour change unless a prop is set.

Test plan

Automatedlist-page.spec.tsx (new) mocks PaginatedListDataTable and asserts ListPage forwards the three props (identity for transformQueryKey, non-default false for includeSelectionColumn), plus a negative case asserting they stay undefined when not provided. This is a RED→GREEN guard for the exact omission: without the fix, transformQueryKey arrives undefined.

✓ src/lib/framework/page/list-page.spec.tsx (2 tests)
Full dashboard unit suite: 479 passed | 4 skipped
check-types: clean

The downstream refetch behaviour lives in PaginatedListDataTable + react-query (unchanged here), which already consumes transformQueryKey to build the query key.

Manual — a ListPage using transformVariables + transformQueryKey to inject toolbar state now refetches when that state changes instead of serving the stale first page.

Fixes #5026


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

grolmus added 2 commits July 30, 2026 11:58
ListPage built its commonTableProps object from most of its props but omitted
transformQueryKey, disableViewOptions and includeSelectionColumn, so those
PaginatedListDataTable props could never be set through ListPage. The
transformQueryKey gap is the harmful one: a page that injects state via
transformVariables cannot keep the react-query cache key in sync, so the list
fetches once and then serves that first response for every value of the
injected state, with no error and no empty table. Forward all three props.

Fixes vendurehq#5026
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
vendure-storybook Ready Ready Preview Aug 4, 2026 10:18am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

ListPageProps now accepts transformQueryKey, disableViewOptions, and includeSelectionColumn. ListPage extracts these values and forwards them to PaginatedListDataTable. New Vitest coverage verifies that configured values are forwarded.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the primary change: forwarding query-key and view-option props from ListPage.
Description check ✅ Passed The description explains the change, root cause, issue, tests, and behavior; omitted template checklist items are non-critical.
Linked Issues check ✅ Passed The PR forwards transformQueryKey, disableViewOptions, and includeSelectionColumn and adds tests for the linked issue requirements [#5026].
Out of Scope Changes check ✅ Passed The changes are limited to ListPage prop forwarding and focused unit tests, with no unrelated code changes identified.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/dashboard/src/lib/framework/page/list-page.spec.tsx (1)

5-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use Readonly<> for the mocked component props.

Type the mock props as Readonly<Record<string, unknown>> to prevent accidental mutation and comply with the dashboard props guideline.

As per coding guidelines, React component props objects should use Readonly<> for type safety.

Proposed diff
-const captured: { props?: Record<string, any> } = {};
+const captured: { props?: Readonly<Record<string, unknown>> } = {};

 vi.mock('`@/vdb/components/shared/paginated-list-data-table.js`', () => ({
-    PaginatedListDataTable: (props: Record<string, any>) => {
+    PaginatedListDataTable: (props: Readonly<Record<string, unknown>>) => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/dashboard/src/lib/framework/page/list-page.spec.tsx` around lines 5
- 13, Update the mocked PaginatedListDataTable component in the test to accept
props typed as Readonly<Record<string, unknown>> instead of a mutable
Record<string, any>. Keep captured.props compatible with the updated props type
and preserve the existing capture behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/dashboard/src/lib/framework/page/list-page.spec.tsx`:
- Around line 5-13: Update the mocked PaginatedListDataTable component in the
test to accept props typed as Readonly<Record<string, unknown>> instead of a
mutable Record<string, any>. Keep captured.props compatible with the updated
props type and preserve the existing capture behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5ea7f701-13a4-42ea-a27e-9f17556da755

📥 Commits

Reviewing files that changed from the base of the PR and between fe68a92 and d5c66dc.

📒 Files selected for processing (2)
  • packages/dashboard/src/lib/framework/page/list-page.spec.tsx
  • packages/dashboard/src/lib/framework/page/list-page.tsx

@michaelbromley michaelbromley added the T1: Fast track Clearly understood fix with limited blast radius. Fast lane. label Jul 30, 2026

@biggamesmallworld biggamesmallworld left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix looks right — I diffed every PaginatedListDataTableProps prop against commonTableProps and after this change all 27 are accounted for. The @default true claim on includeSelectionColumn checks out against use-generated-columns.tsx:82.

Two issues in the spec, both with committable suggestions below.

The second test can never fail. I ran the spec with the fix reverted: Tests 1 failed | 1 passeddoes not inject the forwarded props when they are not provided passes identically before and after. It asserts undefined === undefined, and because of the captured.props?. optional chaining it would also pass if ListPage rendered nothing at all.

React.createElement(ListPage as any, ...) casts away the half of the bug that mattered. The omission was in three places, one of which was the ListPageProps interface. With as any, the test goes green even if you add the props to commonTableProps and forget the interface — public API still broken, guard still says fine. JSX with the props inline gets check-types covering that half.

Also a stray // eslint-disable-next-line import/first — that rule isn't configured in .eslintrc.js (only import/order is), and vitest hoists vi.mock so the bottom-of-file import is unnecessary anyway.

Verified the suggested version locally:

  • GREEN: 1 passed
  • Runtime RED (drop the three props from commonTableProps): AssertionError: expected undefined to be [Function transformQueryKey]
  • Type RED (drop transformQueryKey from ListPageProps only): list-page.spec.tsx(49,17): error TS2322: ... not assignable to ... ListPageProps<...>

Both halves of the regression now guarded.


Non-blocking, for a follow-up: this class of bug exists because every pass-through prop has to be hand-maintained in three places — the ListPageProps interface, the destructuring, and the commonTableProps literal. #5026 wasn't "someone forgot transformQueryKey", it was "the shape guarantees someone forgets something eventually". Deriving the pass-through subset via Pick<PaginatedListDataTableProps<...>, ...> and forwarding by rest-spread would make it unrepresentable. Not asking for that in a master bug fix, but worth an issue.

A behavioural test (render the real PaginatedListDataTable with a stubbed useQuery, assert the query key changes when injected state changes) would cover the actual #5026 symptom rather than just the forwarding. Optional — the forwarding guard is the regression that matters.

Comment thread packages/dashboard/src/lib/framework/page/list-page.spec.tsx Outdated
Comment thread packages/dashboard/src/lib/framework/page/list-page.tsx Outdated

@biggamesmallworld biggamesmallworld left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving on the production change — the prop forwarding is correct and complete (all 27 PaginatedListDataTableProps props accounted for in commonTableProps after this).

Please commit the spec suggestion above before merging. As it stands the second test passes with the fix reverted, and the as any means the ListPageProps interface half of the regression is unguarded — so the current spec would not catch a recurrence of half of #5026. The suggested version is verified RED→GREEN on both halves locally.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/dashboard/src/lib/framework/page/list-page.spec.tsx (1)

34-37: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Type baseProps as readonly props.

baseProps is passed to <ListPage>, but its type is inferred as mutable. Use an explicit Readonly<...> type for this fixture to prevent accidental mutation at compile time.

As per coding guidelines: “Set React component props objects to Readonly<> type for type safety.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/dashboard/src/lib/framework/page/list-page.spec.tsx` around lines 34
- 37, Declare the baseProps fixture with an explicit Readonly props type
matching ListPage’s expected props, while preserving its existing values and
behavior. Update the baseProps declaration rather than the route, title, or
listQuery fields.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/dashboard/src/lib/framework/page/list-page.spec.tsx`:
- Around line 34-37: Declare the baseProps fixture with an explicit Readonly
props type matching ListPage’s expected props, while preserving its existing
values and behavior. Update the baseProps declaration rather than the route,
title, or listQuery fields.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6b76943b-c8a0-4541-a358-552390f8589e

📥 Commits

Reviewing files that changed from the base of the PR and between d5c66dc and c6a84c0.

📒 Files selected for processing (2)
  • packages/dashboard/src/lib/framework/page/list-page.spec.tsx
  • packages/dashboard/src/lib/framework/page/list-page.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/dashboard/src/lib/framework/page/list-page.tsx

@biggamesmallworld
biggamesmallworld merged commit b9b1de3 into vendurehq:master Aug 4, 2026
35 of 37 checks passed
@vendure-ci-automation-bot vendure-ci-automation-bot Bot locked and limited conversation to collaborators Aug 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

T1: Fast track Clearly understood fix with limited blast radius. Fast lane.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ListPage does not forward transformQueryKey to PaginatedListDataTable, so transformVariables-injected state serves a stale cache

3 participants