Skip to content

DataGrid - Summary - Refactor getSummaryOptions() - #34864

Open
Tucchhaa wants to merge 9 commits into
DevExpress:mainfrom
Tucchhaa:refactor_summary_optiobs_26_2
Open

DataGrid - Summary - Refactor getSummaryOptions()#34864
Tucchhaa wants to merge 9 commits into
DevExpress:mainfrom
Tucchhaa:refactor_summary_optiobs_26_2

Conversation

@Tucchhaa

Copy link
Copy Markdown
Contributor

No description provided.

@Tucchhaa Tucchhaa self-assigned this Aug 21, 2026
Copilot AI lite review requested due to automatic review settings August 21, 2026 10:32
@Tucchhaa
Tucchhaa requested a review from a team as a code owner August 21, 2026 10:32
@Tucchhaa Tucchhaa added the 26_2 label Aug 21, 2026
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) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

all cases were added to tests/find_summary_item.tests.ts

}
}

private summary(summary?) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It was used as setter only in QUnit

Comment on lines -437 to -449
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;
}

@Tucchhaa Tucchhaa Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Copilot AI 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.

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 under summary/utils/.
  • Simplified summary_data_controller by removing duplicated summary-option/aggregate-building logic and using the new findSummaryItem helper 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.

Comment thread packages/devextreme/js/__internal/grids/data_grid/summary/types.ts
Copilot AI review requested due to automatic review settings August 21, 2026 10:48

Copilot AI 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.

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

  • getSummaryOptions is wired with getUpdatedItemData: (data) => this._editingController.getUpdatedData(data), but _editingController is obtained via getController('editing') and can be undefined in modular setups/tests where the editing module is not included. If summary.recalculateWhileEditing is 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');

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.

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

@Tucchhaa Tucchhaa Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

dataSourceAdapter is actually a controller:

export default class DataSourceAdapter extends modules.Controller {

So to me it is ok that it uses columnsController.

I think the real issue is:

  1. that dataSourceAdapter acts as both a controller and a dataSource
  2. 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

Comment thread packages/devextreme/js/__internal/grids/data_grid/summary/m_summary.ts Outdated
import { findSummaryItem } from './find_summary_item';
import { getGroupAggregates } from './get_group_aggregates';

export interface GetSummaryOptionsArgs {

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.

Can we move the interfaces and types to types.ts?

@Tucchhaa Tucchhaa Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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

Copilot AI review requested due to automatic review settings August 21, 2026 13:48

Copilot AI 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.

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() passes getUpdatedItemData: (data) => this.editingController.getUpdatedData(data) unconditionally. getController('editing') can be undefined in some configurations (other modules guard it), so enabling summary.recalculateWhileEditing could throw at runtime when editingController is 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(),

Copilot AI review requested due to automatic review settings August 21, 2026 13:56

Copilot AI 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.

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

  • isLastLevelGroupItemsPagingLocal calls summary?.sortByGroups() which only guards summary, not the sortByGroups function. If getSummary() ever returns an object without sortByGroups (e.g., tests overriding getSummary / adapter stubs), this will throw a TypeError. Safer is summary?.sortByGroups?.() (or typeof 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

  • getSummaryOptions is wired with getUpdatedItemData: (data) => this.editingController.getUpdatedData(data) but editingController can be absent (this file already guards it in calculateAggregates). If summary.recalculateWhileEditing is 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 make editingController optional in EditingControllerRequired and 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

  • setSummary overrides dataSourceAdapter.getSummary to return the provided object, but the adapter code expects a SummaryOptions-like shape with a callable sortByGroups. Several tests pass only { groupAggregates, totalAggregates }, which can crash when isLastLevelGroupItemsPagingLocal() calls summary.sortByGroups(). Consider defaulting sortByGroups here (e.g., wrap the provided object and add sortByGroups: () => [] when missing).
    dataSourceAdapter.setSummary = (summary) => {
        dataSourceAdapter.getSummary = () => summary;
    };

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants