Summary
DataViewExportTrigger (and therefore the DataGridAutoExport button every toolbar ships) builds its unpaged export query from filtering.resolvedWhere only. The grid's static filter prop never reaches the export query, so the exported file contains rows from outside the grid's visible scope — a data leak on any statically scoped list ("non-archived contacts", "sessions of this program"). On HasManyDataGrid the export degenerates further: it issues a root list query over the whole target entity table, unscoped to the parent record.
Related toolbar gap that forces downstream recomposition: DataGridToolbarUI hard-codes <DataGridAutoExport /> in its right-hand chrome with no slot/prop to replace or configure it, and the DataGridShowFiltersContext it feeds the mobile filter chips is not exported publicly — a consumer that needs a different export control has to rebuild the whole toolbar and lose the mobile filters toggle.
Environment
Reproduction
<DataGrid entity={articleDef} filter={{ status: { eq: 'published' } }}>
{it => (
<>
<DataGridTextColumn field={it.title} header="Title" />
<DataViewExportTrigger><button>Export</button></DataViewExportTrigger>
<TestTable />
</>
)}
</DataGrid>
The grid's own data load carries { status: { eq: 'published' } }; clicking Export issues a list query whose filter is undefined — the file contains draft articles the operator never saw.
Expected behavior
The export query is constrained exactly like the grid's data load: staticFilter AND resolvedWhere (setup.combinedFilter), and on HasManyDataGrid scoped to the parent relation. Exporting more than the grid can ever display is never correct.
Actual behavior
DataViewExportTrigger.handleExport (packages/bindx-dataview/src/export.tsx, 0.1.46 lines 124–143) sends filter: filtering.resolvedWhere. The DataViewContext exposes only filtering — staticFilter stays private to useDataGridSetup/DataGridImpl (combinedFilter), so not even a custom trigger can reconstruct the correct scope from context. useDataViewFetchAllData() has the same gap. No error — silently over-broad output.
Suspected root cause
DataViewContextValue carries no static/combined filter; the export path was written against user filters only. HasManyDataGrid.tsx additionally publishes entityType: targetEntityType while loading through the parent relation, so the export trigger's root list query has no parent constraint at all.
Suggested fix
Expose the combined filter through the context (e.g. resolvedFilter alongside filtering), use it in DataViewExportTrigger/useDataViewFetchAllData, and disable (or parent-scope) the export in HasManyDataGrid. Independently: give DataGridToolbarUI a slot (or prop) for the export control and export DataGridShowFiltersContext publicly, so consumers can swap the export without rebuilding the toolbar.
Workaround shipped downstream
We applied a temporary workaround in our project, marked TODO [BindX] (<this-issue-url>): <description>. The workaround recomposes the toolbar from public parts (dropping the mobile filters toggle, whose context is unexported) and replaces the export with a custom control that combines the wrapper-provided static filter with filtering.resolvedWhere and hides itself in has-many grids; we will remove it once this issue is resolved.
Summary
DataViewExportTrigger(and therefore theDataGridAutoExportbutton every toolbar ships) builds its unpaged export query fromfiltering.resolvedWhereonly. The grid's staticfilterprop never reaches the export query, so the exported file contains rows from outside the grid's visible scope — a data leak on any statically scoped list ("non-archived contacts", "sessions of this program"). OnHasManyDataGridthe export degenerates further: it issues a root list query over the whole target entity table, unscoped to the parent record.Related toolbar gap that forces downstream recomposition:
DataGridToolbarUIhard-codes<DataGridAutoExport />in its right-hand chrome with no slot/prop to replace or configure it, and theDataGridShowFiltersContextit feeds the mobile filter chips is not exported publicly — a consumer that needs a different export control has to rebuild the whole toolbar and lose the mobile filters toggle.Environment
@contember/bindx@0.1.46(version installed in the reporting project)contember/bindx@mainas of3c2fd0dtests/react/dataview/exportIgnoresStaticFilter.test.tsxbug/export-ignores-static-filterReproduction
The grid's own data load carries
{ status: { eq: 'published' } }; clicking Export issues a list query whosefilterisundefined— the file contains draft articles the operator never saw.Expected behavior
The export query is constrained exactly like the grid's data load:
staticFilter AND resolvedWhere(setup.combinedFilter), and onHasManyDataGridscoped to the parent relation. Exporting more than the grid can ever display is never correct.Actual behavior
DataViewExportTrigger.handleExport(packages/bindx-dataview/src/export.tsx, 0.1.46 lines 124–143) sendsfilter: filtering.resolvedWhere. TheDataViewContextexposes onlyfiltering—staticFilterstays private touseDataGridSetup/DataGridImpl(combinedFilter), so not even a custom trigger can reconstruct the correct scope from context.useDataViewFetchAllData()has the same gap. No error — silently over-broad output.Suspected root cause
DataViewContextValuecarries no static/combined filter; the export path was written against user filters only.HasManyDataGrid.tsxadditionally publishesentityType: targetEntityTypewhile loading through the parent relation, so the export trigger's root list query has no parent constraint at all.Suggested fix
Expose the combined filter through the context (e.g.
resolvedFilteralongsidefiltering), use it inDataViewExportTrigger/useDataViewFetchAllData, and disable (or parent-scope) the export inHasManyDataGrid. Independently: giveDataGridToolbarUIa slot (or prop) for the export control and exportDataGridShowFiltersContextpublicly, so consumers can swap the export without rebuilding the toolbar.Workaround shipped downstream
We applied a temporary workaround in our project, marked
TODO [BindX] (<this-issue-url>): <description>. The workaround recomposes the toolbar from public parts (dropping the mobile filters toggle, whose context is unexported) and replaces the export with a custom control that combines the wrapper-provided static filter withfiltering.resolvedWhereand hides itself in has-many grids; we will remove it once this issue is resolved.