Skip to content

Conversation

@Raushen
Copy link
Contributor

@Raushen Raushen commented Jan 13, 2026

No description provided.

@Raushen Raushen self-assigned this Jan 13, 2026
@Raushen Raushen requested a review from a team as a code owner January 13, 2026 22:42
Copilot AI review requested due to automatic review settings January 13, 2026 22:42
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a bug (T1311329) where the DataGrid column chooser incorrectly hides a banded (parent) column when using search functionality with recursive selection enabled. The issue occurred because column visibility was being updated without considering the relationship between banded columns and their children.

Changes:

  • Refactored column visibility update logic to handle banded columns correctly by processing them in sorted order (non-band columns first, then band columns)
  • Added integration tests to verify the fix for both the search scenario and direct toggling of banded columns
  • Created reusable test model classes (TreeViewModel, TextBoxModel, CheckBoxModel, ColumnChooserModel) to support the new tests

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/devextreme/js/__internal/grids/grid_core/column_chooser/m_column_chooser.ts Refactored column visibility logic to correctly handle banded columns by sorting nodes and determining visibility based on child column states
packages/devextreme/js/__internal/grids/grid_core/column_chooser/tests/column_chooser.integration.test.ts Added comprehensive integration tests for the banded column visibility fix
packages/devextreme/js/__internal/grids/grid_core/tests/mock/model/grid_core.ts Added getColumnChooser method to support column chooser testing
packages/devextreme/js/__internal/grids/grid_core/tests/mock/model/column_chooser.ts Created model class for interacting with column chooser in tests
packages/devextreme/js/__internal/ui/tests/mock/model/tree_view.ts Created reusable model for TreeView interactions in tests
packages/devextreme/js/__internal/ui/tests/mock/model/textbox.ts Created reusable model for TextBox interactions in tests
packages/devextreme/js/__internal/ui/tests/mock/model/checkbox.ts Created reusable model for CheckBox interactions in tests

Copilot AI review requested due to automatic review settings January 15, 2026 02:25
Copy link
Contributor

Copilot AI left a comment

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 7 out of 7 changed files in this pull request and generated 3 comments.

Copilot AI review requested due to automatic review settings January 15, 2026 03:21
Copy link
Contributor

Copilot AI left a comment

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 7 out of 7 changed files in this pull request and generated 3 comments.

Copilot AI review requested due to automatic review settings January 16, 2026 06:32
Copy link
Contributor

Copilot AI left a comment

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 7 out of 7 changed files in this pull request and generated 6 comments.

Comment on lines +53 to +56
const dataGrid = ($container as any).dxDataGrid('instance') as DataGrid;

dataGrid.dispose();
$container.remove();
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

The cleanup function assumes a DataGrid instance always exists, which may not be true if a test fails early or during grid creation. Add a null check before calling dispose to prevent errors during cleanup. Consider checking if the container exists and has a DataGrid instance before attempting disposal.

Suggested change
const dataGrid = ($container as any).dxDataGrid('instance') as DataGrid;
dataGrid.dispose();
$container.remove();
if ($container.length) {
const hasDxDataGrid = typeof ($container as any).dxDataGrid === 'function';
const dataGrid = hasDxDataGrid
? ($container as any).dxDataGrid('instance') as DataGrid | undefined
: undefined;
if (dataGrid) {
dataGrid.dispose();
}
$container.remove();
}

Copilot uses AI. Check for mistakes.
Comment on lines +22 to +31
return new TextBoxModel(this.root?.querySelector(`.${CLASSES.searchBox}`) as HTMLElement);
}

public setSearchValue(value: string): void {
const searchBox = this.getSearchBox();
searchBox.setValue(value);
}

private getNodes(): NodeListOf<HTMLElement> | null {
return this.root?.querySelectorAll(`.${CLASSES.node}`) ?? null;
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

The root parameter is defined as non-nullable (protected readonly root: HTMLElement), but the code uses optional chaining (this.root?.querySelector). Since root cannot be null or undefined, the optional chaining is unnecessary and can be simplified to this.root.querySelector.

Copilot uses AI. Check for mistakes.
return result;
}, flatNodesArray);

// Band columns should be updated after regular columns
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

The comment "Band columns should be updated after regular columns" explains why the array is reversed, but the implementation may be incomplete. When reversing a flattened tree, parent nodes will be processed before their children. However, in a multi-level banded column hierarchy (3+ levels), you need to ensure that the deepest children are processed first, then their parents, then grandparents, etc. The current implementation reverses the depth-first traversal order, which should work correctly. Consider adding a more detailed comment explaining that reversing a depth-first traversal ensures children are processed before parents.

Suggested change
// Band columns should be updated after regular columns
// NOTE:
// getNodeLevelPairsRecursive performs a depth-first traversal that flattens the
// banded column tree in "parent before children" order. Reversing this flat list
// produces an update order where the deepest child columns are processed first,
// then their parents, then grandparents, etc.
//
// This guarantees that regular (leaf) columns are updated before band columns,
// even in multi-level banded hierarchies (3+ levels), so that parent band
// visibility is computed after all of its descendants.

Copilot uses AI. Check for mistakes.
}

public setValue(value: string): void {
this.getInstance()?.option('value', value);
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

The setValue method uses the widget API (getInstance().option('value', value)) which may not trigger all the same events as user input. For consistency with the existing TextAreaModel pattern, consider also dispatching an 'input' event to ensure all change handlers are triggered. This is important for testing components that rely on DOM events rather than widget option changes.

Suggested change
this.getInstance()?.option('value', value);
this.getInstance()?.option('value', value);
const inputElement = this.root.querySelector<HTMLInputElement>('.dx-texteditor-input, input');
if (inputElement) {
const event = new Event('input', { bubbles: true, cancelable: true });
inputElement.dispatchEvent(event);
}

Copilot uses AI. Check for mistakes.
Comment on lines +182 to +209
{
dataField: 'data1_level1',
},
],
});

let visibleColumnsLevel0 = instance.getVisibleColumns(0);
let visibleColumnsLevel1 = instance.getVisibleColumns(1);
let visibleColumnsLevel2 = instance.getVisibleColumns(2);

expect(visibleColumnsLevel0.find((col) => col.caption === 'band_level1')).toBeDefined();
expect(visibleColumnsLevel0.find((col) => col.dataField === 'data1_level1')).toBeDefined();
expect(visibleColumnsLevel1.find((col) => col.dataField === 'data1_level2')).toBeDefined();
expect(visibleColumnsLevel1.find((col) => col.dataField === 'data2_level2')).toBeDefined();
expect(visibleColumnsLevel1.find((col) => col.caption === 'band_level2')).toBeDefined();
expect(visibleColumnsLevel2.find((col) => col.dataField === 'data1_level3')).toBeUndefined();
expect(visibleColumnsLevel2.find((col) => col.dataField === 'data2_level3')).toBeDefined();

instance.showColumnChooser();
jest.runAllTimers();

const columnChooser = component.getColumnChooser();
expect(columnChooser.isVisible()).toBe(true);

columnChooser.searchColumn('1');
jest.runAllTimers();

columnChooser.toggleColumn('Data 1 level 1');
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

The test relies on DataGrid's auto-generated caption for the column with dataField: 'data1_level1'. While DataGrid does auto-generate captions from dataFields (converting underscores to spaces and capitalizing), explicitly setting a caption would make the test more readable and less fragile to potential changes in the caption generation logic. Consider adding an explicit caption property to make the test's intent clearer.

Copilot uses AI. Check for mistakes.
}

private _getSortedFlatNodes(nodes: NodeInternal[]): NodeInternal[] {
const getNodeLevelPairsRecursive = (
Copy link
Contributor

Choose a reason for hiding this comment

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

this utility not returns node-level pairs any more, let's rename it to smth like flattenNodesDepthFirst to show the order is important

also method _getSortedFlatNodes has incorrect name too - we do no sort any more

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.

3 participants