Skip to content

DataViewExportTrigger ignores the grid's static filter (and parent scope in HasManyDataGrid); toolbar export control is not replaceable #67

Description

@vparys

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 filteringstaticFilter 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions