Skip to content

DataGridServer on MUI's data source; getRows; rowCount defunct (0.2.0) - #19

Merged
lgnbhl merged 6 commits into
mainfrom
refactor/thin-server-side
Oct 21, 2026
Merged

lgnbhl merged 6 commits into
mainfrom
refactor/thin-server-side

Conversation

@lgnbhl

@lgnbhl lgnbhl commented Oct 21, 2026

Copy link
Copy Markdown
Owner

Rebuilds DataGridServer() on MUI X Data Grid's own server-side data source and releases it as 0.2.0, which includes one breaking change.

What changes

  • MUI owns the grid state. Pagination, sort and filter state, the reset to page 1, the loading overlay and the handling of stale responses are now MUI's (dataSource, MIT edition). The custom controlled-state layer is gone.
  • Each page is answered over HTTP. The grid POSTs every request to an endpoint scoped to the Shiny session (session$registerDataObj(), as DT does). rows = <full data> works as before, but paging no longer re-runs renderReact(). An error while producing a page is reported in the R console and the request fails cleanly; the output no longer breaks.
  • New getRows argument. It's MUI's getRows contract in R: a function of the request returning list(rows, rowCount), the shape processGridParams() already returns.
  • Filter code in R is table-driven: one entry per MUI operator.

Breaking

  • rowCount is defunct. It now errors and points to getRows. That mode re-rendered a pre-sliced page from input$<inputId>, so the rows could belong to a different request than the one the footer showed.
  • Smaller changes:
    • input$<inputId>$filter_model$items now holds only the filters MUI applies.
    • The server-mode props are forced by MUI rather than set by R.
    • Two grids sharing an inputId no longer raise an error.

All breaking changes are listed in NEWS, and the vignette has a "Migrating from rowCount" section.

Bugs fixed (wrong rows or counts)

  • The date is filter matched nothing ("0 of 0"); not matched everything.
  • An initialState with only pageSize showed "No results found." under a "1–25 of 500" footer.
  • autoPageSize was ignored, so the grid showed 100 rows.
  • The boolean is filter matched nothing; emptied filters blanked the grid.

The initialState and autoPageSize bugs were confirmed by running main in a headless browser.

Testing

  • R tests: all pass, including tests of the HTTP endpoint, getRows and the rowCount error.
  • R CMD check --as-cran: 0 errors, 0 warnings. The only note ("unable to verify current time") comes from the machine.
  • shinytest2 in headless Chrome: paging, filters (including dates), sorting, the quick filter with hidden columns, initialState, autoPageSize, filterDebounceMs, data changing in R, a slow getRows backend with rapid clicks, two grids in Shiny modules, and a static HTML page.
  • Not tested: shinylive/webR.

🤖 Generated with Claude Code

lgnbhl and others added 6 commits October 21, 2026 17:05
…ters

* Date is/not filters now match: MUI sends the date picker value as a
  timestamp ("2024-01-15T00:00:00.000Z"), which never equalled the column.
* Quick filter follows MUI: searches only the visible columns the grid
  sends as quick_filter_fields, matches number columns by value, skips
  boolean columns. Previously it also searched undisplayed columns.
* Opening the filter panel or picking an operator without a value no
  longer resets to page 0 or triggers a round-trip; an initialState quick
  filter is applied on first render.
* processGridParams() filter operators are a table of one entry each;
  the memo cache key includes quick_filter_fields.
* Require muiMaterial >= 0.2.1 and keep .MUIMATERIAL_MIN_VERSION in sync.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The grid component now hands pagination, sort and filter state to MUI's
own `dataSource` (stable, MIT edition) instead of a custom controlled
state layer. MUI owns the page reset, the loading overlay and stale
response handling; the component only bridges getRows() to Shiny:

* Each request is posted as input$<inputId> with a request_id, which
  DataGridServer() echoes back so the matching R render resolves it.
* Requests that cannot change R's answer (filter panel opened, inactive
  items, the first request on mount) are answered locally.
* A request is held 50 ms so MUI's sort/filter + page-reset pair reaches
  R once instead of twice.
* An R render that answers no request (data changed) updates the page
  in place.

R API unchanged. filterDebounce maps to MUI's filterDebounceMs. The
duplicate-inputId check is removed (as for any Shiny input).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The grid requests its first page from R on mount like any other page;
  R no longer guesses it from initialState, so autoPageSize and a
  pageSize-only initialState open on the right page. Without a session
  (static documents) R still renders the first page.
* Use MUI's gridFilterActiveItemsSelector instead of a copy of its rule;
  input$<inputId> now carries only the filter items MUI applies.
* Stop sending paginationMode/sortingMode/filterMode/pagination: MUI's
  data source forces them. Passing them still warns.
* filterDebounceMs passed via ... takes precedence over filterDebounce.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
* DataGridServer() answers MUI's getRows() through a session-scoped HTTP
  endpoint (session$registerDataObj(), as DT does) instead of
  re-rendering the grid per page. The rows = <full data> call is
  unchanged; paging no longer re-runs renderReact(), a re-render (new
  data) reloads the current page, and errors are reported in the console
  and as a 500 instead of breaking the output.
* New getRows argument mirrors MUI's dataSource.getRows: a function of
  the request returning list(rows, rowCount), the shape
  processGridParams() returns. Requires columns.
* Passing a pre-sliced page with rowCount is deprecated (warning once per
  session). It keeps the input$<inputId> + request_id bridge, isolated
  in useInputBridge() for removal together with rowCount.
* Test sessions (no HTTP endpoints) render the requested page as before.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
BREAKING CHANGE: DataGridServer(rows = <page>, rowCount = n) now errors
with directions to `getRows`. In that mode the rows came from whatever
input R had last read while the footer described the user's current
page, so a slow or debounced reactive could show another request's rows.
getRows answers each request directly and cannot drift.

Removes the input$<inputId> + request_id bridge (useInputBridge, the
requestId echo and the deprecation warning). NEWS now separates breaking
changes, new features and the "wrong rows or counts shown" bug fixes,
including the initialState pageSize-only and autoPageSize ones confirmed
against main in the browser.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 94.04762% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.79%. Comparing base (9e8721f) to head (c5ddcaf).

Files with missing lines Patch % Lines
R/components.R 94.04% 10 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #19      +/-   ##
==========================================
- Coverage   98.10%   96.79%   -1.32%     
==========================================
  Files           4        4              
  Lines         369      405      +36     
==========================================
+ Hits          362      392      +30     
- Misses          7       13       +6     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@lgnbhl
lgnbhl merged commit 56ad0e8 into main Oct 21, 2026
8 checks passed
@lgnbhl
lgnbhl deleted the refactor/thin-server-side branch October 21, 2026 16:26
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.

2 participants