DataGrid - Summary - Refactor getSummaryOptions() - #34864
Conversation
| assert.deepEqual(headerFilterItems.map(function(item) { return item.value; }), [15, 18, 19, 20, 25], 'items are sorted'); | ||
| }); | ||
|
|
||
| QUnit.test('findSummaryItem by custom name', function(assert) { |
There was a problem hiding this comment.
all cases were added to tests/find_summary_item.tests.ts
| } | ||
| } | ||
|
|
||
| private summary(summary?) { |
There was a problem hiding this comment.
It was used as setter only in QUnit
| protected _createDataSourceAdapter(dataSource: DataSource) { | ||
| const dataSourceAdapter = super._createDataSourceAdapter(dataSource); | ||
|
|
||
| // @ts-expect-error summaryGetter is defined in summary DataSourceAdapterExtender | ||
| dataSourceAdapter.summaryGetter((currentRemoteOperations) => { | ||
| const result = this._getSummaryOptions( | ||
| currentRemoteOperations ?? dataSourceAdapter.remoteOperations(), | ||
| ); | ||
| return result; | ||
| }); | ||
|
|
||
| return dataSourceAdapter; | ||
| } |
There was a problem hiding this comment.
replaced this function by a simple getter in summaryDataSourceAdapterExtender:
https://github.com/DevExpress/DevExtreme/pull/34864/changes#diff-d57264845ac30f8d19ae92cce36b829978453305efb72ed33d907e6208d7f112R303
There was a problem hiding this comment.
Pull request overview
Refactors DataGrid summary option construction by extracting the logic into reusable utilities and moving summary-option generation into the Summary DataSourceAdapter extender, while shifting coverage from a removed QUnit internal-method test to new Jest unit tests for the extracted helpers.
Changes:
- Extracted summary option building (
getSummaryOptions), group-aggregate access, and summary-item lookup into dedicated utils undersummary/utils/. - Simplified
summary_data_controllerby removing duplicated summary-option/aggregate-building logic and using the newfindSummaryItemhelper for total summary lookups. - Updated tests: adjusted DataSource QUnit tests to use a helper setter and added Jest coverage for the new utilities.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/dataSource.tests.js | Adds a test helper (setSummary) and updates call sites to match the refactor. |
| packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/dataController.tests.js | Removes QUnit coverage for an internal summary lookup method that was refactored out. |
| packages/devextreme/js/__internal/grids/data_grid/summary/utils/get_summary_options.ts | New core utility that builds local/remote aggregate descriptors and sort-by-group summary info. |
| packages/devextreme/js/__internal/grids/data_grid/summary/utils/get_group_aggregates.ts | New helper to read group aggregates from summary/aggregates fields. |
| packages/devextreme/js/__internal/grids/data_grid/summary/utils/find_summary_item.ts | New helper to resolve a summary item index by several supported identifiers. |
| packages/devextreme/js/__internal/grids/data_grid/summary/utils/tests/get_summary_options.test.ts | Adds Jest coverage for getSummaryOptions behavior. |
| packages/devextreme/js/__internal/grids/data_grid/summary/utils/tests/find_summary_item.test.ts | Adds Jest coverage for findSummaryItem. |
| packages/devextreme/js/__internal/grids/data_grid/summary/types.ts | Updates summary-related internal types and introduces aggregate/sort types. |
| packages/devextreme/js/__internal/grids/data_grid/summary/summary_module.ts | Adds explicit typing for defaultOptions() return shape. |
| packages/devextreme/js/__internal/grids/data_grid/summary/m_summary.ts | Removes summaryGetter/summary plumbing and uses getSummaryOptions directly in the adapter extender. |
| packages/devextreme/js/__internal/grids/data_grid/summary/extenders/summary_data_controller.ts | Removes summary-option construction logic from the controller extender and switches to shared helpers. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.
Suppressed comments (1)
packages/devextreme/js/__internal/grids/data_grid/summary/m_summary.ts:314
getSummaryOptionsis wired withgetUpdatedItemData: (data) => this._editingController.getUpdatedData(data), but_editingControlleris obtained viagetController('editing')and can beundefinedin modular setups/tests where the editing module is not included. Ifsummary.recalculateWhileEditingis enabled in that scenario, selectors will throw at runtime. Consider guarding this with an identity fallback (e.g.this._editingController?.getUpdatedData ? ... : data).
sortByGroupSummaryInfo: this.option('sortByGroupSummaryInfo'),
remoteOperations: remoteOperations ?? this.remoteOperations(),
getUpdatedItemData: (data) => this._editingController.getUpdatedData(data),
columnOption: (id) => this._columnsController.columnOption(id),
groupColumns: this._columnsController.getGroupColumns(),
| public init(dataSource?: DataSource): void { | ||
| super.init(dataSource); | ||
|
|
||
| this._columnsController = this.getController('columns'); |
There was a problem hiding this comment.
it is confusing that dataAdapter knows smth about grid controllers
I'm not sure we can resolve it right now, please, investigate on possible solutions
There was a problem hiding this comment.
dataSourceAdapter is actually a controller:
So to me it is ok that it uses columnsController.
I think the real issue is:
- that dataSourceAdapter acts as both a controller and a dataSource
- and that dataSourceAdapter and dataController have overlapping responsibilities
So I think ideally we need to define what is dataSourceAdapter exactly and then refactor it. Right now, it would be hard to remove columnController/editingController deps from summaryDataSourceAdapterExtender
| import { findSummaryItem } from './find_summary_item'; | ||
| import { getGroupAggregates } from './get_group_aggregates'; | ||
|
|
||
| export interface GetSummaryOptionsArgs { |
There was a problem hiding this comment.
Can we move the interfaces and types to types.ts?
There was a problem hiding this comment.
I would prefer to keep both the GetSummaryOptionsArgs and types in this file, because types are very simple and used only here and GetSummaryOptionsArgs interface is needed only when getSummaryOptions is called.
So to avoid polluting types.ts I would keep types in this file, if you dont mind
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.
Suppressed comments (1)
packages/devextreme/js/__internal/grids/data_grid/summary/m_summary.ts:314
getSummary()passesgetUpdatedItemData: (data) => this.editingController.getUpdatedData(data)unconditionally.getController('editing')can be undefined in some configurations (other modules guard it), so enablingsummary.recalculateWhileEditingcould throw at runtime wheneditingControlleris missing. Consider guarding here (e.g.,this.editingController?.getUpdatedData(data) ?? data) or falling back to an identity updater when the controller is not available.
const result = getSummaryOptions({
summary,
sortByGroupSummaryInfo: this.option('sortByGroupSummaryInfo'),
remoteOperations: remoteOperations ?? this.remoteOperations(),
getUpdatedItemData: (data) => this.editingController.getUpdatedData(data),
columnOption: (id) => this.columnsController.columnOption(id),
groupColumns: this.columnsController.getGroupColumns(),
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.
Suppressed comments (3)
packages/devextreme/js/__internal/grids/data_grid/summary/m_summary.ts:331
isLastLevelGroupItemsPagingLocalcallssummary?.sortByGroups()which only guardssummary, not thesortByGroupsfunction. IfgetSummary()ever returns an object withoutsortByGroups(e.g., tests overridinggetSummary/ adapter stubs), this will throw a TypeError. Safer issummary?.sortByGroups?.()(ortypeof summary?.sortByGroups === 'function' && summary.sortByGroups()).
private isLastLevelGroupItemsPagingLocal() {
const summary = this.getSummary();
const sortByGroupsInfo = summary?.sortByGroups();
return sortByGroupsInfo?.length;
packages/devextreme/js/__internal/grids/data_grid/summary/m_summary.ts:314
getSummaryOptionsis wired withgetUpdatedItemData: (data) => this.editingController.getUpdatedData(data)buteditingControllercan be absent (this file already guards it incalculateAggregates). Ifsummary.recalculateWhileEditingis enabled in a build where the editing controller isn't available, selectors will throw at runtime. Consider guarding here as well (e.g.,this.editingController?.getUpdatedData?.(data) ?? data) or makeeditingControlleroptional inEditingControllerRequiredand handle the undefined case explicitly.
This issue also appears on line 327 of the same file.
const result = getSummaryOptions({
summary,
sortByGroupSummaryInfo: this.option('sortByGroupSummaryInfo'),
remoteOperations: remoteOperations ?? this.remoteOperations(),
getUpdatedItemData: (data) => this.editingController.getUpdatedData(data),
columnOption: (id) => this.columnsController.columnOption(id),
groupColumns: this.columnsController.getGroupColumns(),
packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/dataSource.tests.js:63
setSummaryoverridesdataSourceAdapter.getSummaryto return the provided object, but the adapter code expects aSummaryOptions-like shape with a callablesortByGroups. Several tests pass only{ groupAggregates, totalAggregates }, which can crash whenisLastLevelGroupItemsPagingLocal()callssummary.sortByGroups(). Consider defaultingsortByGroupshere (e.g., wrap the provided object and addsortByGroups: () => []when missing).
dataSourceAdapter.setSummary = (summary) => {
dataSourceAdapter.getSummary = () => summary;
};
No description provided.