Skip to content

Commit acc0601

Browse files
authored
✨AI Column: New column type / Unsupported Sorting properties (#31104)
1 parent b672777 commit acc0601

File tree

11 files changed

+252
-0
lines changed

11 files changed

+252
-0
lines changed

packages/devextreme/js/__internal/grids/data_grid/m_widget.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import DataGrid from './m_widget_base';
44

55
import './module_not_extended/state_storing';
6+
import './module_not_extended/ai_column_controller';
67
import './module_not_extended/selection';
78
import './module_not_extended/column_chooser';
89
import './grouping/m_grouping';

packages/devextreme/js/__internal/grids/data_grid/m_widget_base.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const DATAGRID_DEPRECATED_TEMPLATE_WARNING = 'Specifying grid templates with the
2626
gridCore.registerModulesOrder([
2727
'stateStoring',
2828
'columns',
29+
'aiColumn',
2930
'selection',
3031
'editorFactory',
3132
'columnChooser',
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { aiColumnControllerModule } from '@ts/grids/grid_core/ai_column/m_ai_column_controller';
2+
3+
import gridCore from '../m_core';
4+
5+
gridCore.registerModule('aiColumnController', aiColumnControllerModule);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const AI_COLUMN_NAME = 'ai';
2+
3+
export const CLASSES = {
4+
aiColumn: 'dx-command-ai',
5+
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type { ColumnsController } from '../columns_controller/m_columns_controller';
2+
import { Controller } from '../m_modules';
3+
import { getAiCommandColumnOptions } from './m_ai_column_controller_utils';
4+
5+
export class AiColumnController extends Controller {
6+
private columnsController!: ColumnsController;
7+
8+
public init(): void {
9+
this.columnsController = this.getController('columns');
10+
this.addAiCommandColumn();
11+
}
12+
13+
private addAiCommandColumn(): void {
14+
const aiColumnOptions = getAiCommandColumnOptions();
15+
this.columnsController.addCommandColumn(aiColumnOptions);
16+
}
17+
}
18+
19+
export const aiColumnControllerModule = {
20+
controllers: {
21+
aiColumn: AiColumnController,
22+
},
23+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { AI_COLUMN_NAME, CLASSES } from './const';
2+
3+
export const getAiCommandColumnOptions = () => ({
4+
type: AI_COLUMN_NAME,
5+
command: AI_COLUMN_NAME,
6+
cssClass: CLASSES.aiColumn,
7+
});
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
import { beforeEach } from 'node:test';
2+
3+
import {
4+
afterEach, describe, expect, it,
5+
} from '@jest/globals';
6+
import type { dxElementWrapper } from '@js/core/renderer';
7+
import $ from '@js/core/renderer';
8+
import type { Properties as DataGridProperties } from '@js/ui/data_grid';
9+
import DataGrid from '@js/ui/data_grid';
10+
11+
const SELECTORS = {
12+
gridContainer: '#gridContainer',
13+
headerCell: '[aria-colindex]',
14+
};
15+
16+
const GRID_CONTAINER_ID = 'gridContainer';
17+
18+
const createDataGrid = async (
19+
options: DataGridProperties = {},
20+
): Promise<{ $container: dxElementWrapper; instance: DataGrid }> => new Promise((resolve) => {
21+
const $container = $('<div>')
22+
.attr('id', GRID_CONTAINER_ID)
23+
.appendTo(document.body);
24+
25+
const instance = new DataGrid($container.get(0) as HTMLDivElement, {
26+
...options,
27+
});
28+
29+
const contentReadyHandler = (): void => {
30+
resolve({ $container, instance });
31+
instance.off('contentReady', contentReadyHandler);
32+
};
33+
34+
instance.on('contentReady', contentReadyHandler);
35+
});
36+
37+
const getGrid = (): DataGrid => {
38+
const $container = $(SELECTORS.gridContainer);
39+
return ($container as any).dxDataGrid('instance') as DataGrid;
40+
};
41+
42+
const dataSource = [
43+
{ id: 1, name: 'Item 1' },
44+
{ id: 2, name: 'Item 2' },
45+
{ id: 3, name: 'Item 3' },
46+
];
47+
48+
describe('Unsupported properties', () => {
49+
beforeEach(async () => {
50+
51+
});
52+
afterEach(() => {
53+
const dataGrid = getGrid();
54+
55+
dataGrid.dispose();
56+
$(SELECTORS.gridContainer).remove();
57+
});
58+
59+
describe('Sorting properties', () => {
60+
it('should have no sorting state in the header after a click (first load)', async () => {
61+
const { instance } = await createDataGrid({
62+
dataSource,
63+
showBorders: true,
64+
columns: [
65+
'id',
66+
{
67+
caption: 'AI',
68+
type: 'ai',
69+
name: 'AItest',
70+
71+
allowSorting: true,
72+
},
73+
],
74+
});
75+
const $headers = $(instance.element()).find(SELECTORS.headerCell);
76+
const aiTestHeader = $($headers.toArray().find((el) => $(el).text().includes('AI')));
77+
expect(aiTestHeader).toHaveLength(1);
78+
expect(aiTestHeader.attr('aria-colindex')).toEqual('2');
79+
expect(aiTestHeader.attr('aria-sort')).toBeUndefined();
80+
(aiTestHeader.get(0) as HTMLElement).click();
81+
expect(aiTestHeader.attr('aria-sort')).toBeUndefined();
82+
});
83+
it('should have no sorting state in the header after a click (dynamic update)', async () => {
84+
const { instance } = await createDataGrid({
85+
dataSource,
86+
showBorders: true,
87+
columns: [
88+
'id',
89+
{
90+
caption: 'AI',
91+
type: 'ai',
92+
name: 'AItest',
93+
},
94+
],
95+
});
96+
instance.columnOption('AItest', 'allowSorting', true);
97+
const $headers = $(instance.element()).find(SELECTORS.headerCell);
98+
const aiTestHeader = $($headers.toArray().find((el) => $(el).text().includes('AI')));
99+
expect(aiTestHeader).toHaveLength(1);
100+
expect(aiTestHeader.attr('aria-colindex')).toEqual('2');
101+
expect(aiTestHeader.attr('aria-sort')).toBeUndefined();
102+
(aiTestHeader.get(0) as HTMLElement).click();
103+
expect(aiTestHeader.attr('aria-sort')).toBeUndefined();
104+
});
105+
it('should have no sorting state in the header with sortOrder and sortIndex options (first load)', async () => {
106+
const { instance } = await createDataGrid({
107+
dataSource,
108+
showBorders: true,
109+
columns: [
110+
{
111+
dataField: 'id',
112+
sortOrder: 'asc',
113+
sortIndex: 1,
114+
},
115+
{
116+
caption: 'AI',
117+
type: 'ai',
118+
name: 'AItest',
119+
120+
sortOrder: 'asc',
121+
sortIndex: 2,
122+
},
123+
],
124+
});
125+
const $headers = $(instance.element()).find(SELECTORS.headerCell);
126+
const aiTestHeader = $($headers.toArray().find((el) => $(el).text().includes('AI')));
127+
expect(aiTestHeader).toHaveLength(1);
128+
expect(aiTestHeader.attr('aria-colindex')).toEqual('2');
129+
expect(aiTestHeader.attr('aria-sort')).toBeUndefined();
130+
expect(aiTestHeader.attr('aria-roledescription')).toBeUndefined();
131+
});
132+
it('should have no sorting state in the header with sortOrder and sortIndex options (dynamic update)', async () => {
133+
const { instance } = await createDataGrid({
134+
dataSource,
135+
showBorders: true,
136+
columns: [
137+
{
138+
dataField: 'id',
139+
sortOrder: 'asc',
140+
sortIndex: 1,
141+
},
142+
{
143+
caption: 'AI',
144+
type: 'ai',
145+
name: 'AItest',
146+
},
147+
],
148+
});
149+
instance.columnOption('AItest', 'sortOrder', 'asc');
150+
instance.columnOption('AItest', 'sortIndex', 2);
151+
const $headers = $(instance.element()).find(SELECTORS.headerCell);
152+
const aiTestHeader = $($headers.toArray().find((el) => $(el).text().includes('AI')));
153+
expect(aiTestHeader).toHaveLength(1);
154+
expect(aiTestHeader.attr('aria-colindex')).toEqual('2');
155+
expect(aiTestHeader.attr('aria-sort')).toBeUndefined();
156+
expect(aiTestHeader.attr('aria-roledescription')).toBeUndefined();
157+
});
158+
it('should have no sorting state in the header with calculateSortValue (first load)', async () => {
159+
const { instance } = await createDataGrid({
160+
dataSource,
161+
showBorders: true,
162+
columns: [
163+
'id',
164+
{
165+
caption: 'AI',
166+
type: 'ai',
167+
name: 'AItest',
168+
169+
sortOrder: 'asc',
170+
calculateGroupValue: 'name',
171+
},
172+
],
173+
});
174+
const $headers = $(instance.element()).find(SELECTORS.headerCell);
175+
const aiTestHeader = $($headers.toArray().find((el) => $(el).text().includes('AI')));
176+
expect(aiTestHeader).toHaveLength(1);
177+
expect(aiTestHeader.attr('aria-colindex')).toEqual('2');
178+
expect(aiTestHeader.attr('aria-sort')).toBeUndefined();
179+
});
180+
it('should have no sorting state in the header with calculateSortValue (dynamic update)', async () => {
181+
const { instance } = await createDataGrid({
182+
dataSource,
183+
showBorders: true,
184+
columns: [
185+
'id',
186+
{
187+
caption: 'AI',
188+
type: 'ai',
189+
name: 'AItest',
190+
},
191+
],
192+
});
193+
instance.columnOption('AItest', 'sortOrder', 'asc');
194+
instance.columnOption('AItest', 'calculateSortValue', 'name');
195+
const $headers = $(instance.element()).find(SELECTORS.headerCell);
196+
const aiTestHeader = $($headers.toArray().find((el) => $(el).text().includes('AI')));
197+
expect(aiTestHeader).toHaveLength(1);
198+
expect(aiTestHeader.attr('aria-colindex')).toEqual('2');
199+
expect(aiTestHeader.attr('aria-sort')).toBeUndefined();
200+
});
201+
});
202+
});

packages/devextreme/js/__internal/grids/grid_core/m_types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ export interface Controllers {
198198
stateStoring: import('./state_storing/m_state_storing_core').StateStoringController;
199199
synchronizeScrolling: import('./views/m_grid_view').SynchronizeScrollingController;
200200
tablePosition: import('./columns_resizing_reordering/m_columns_resizing_reordering').TablePositionViewController;
201+
aiColumn: import('./ai_column/m_ai_column_controller').AiColumnController;
201202
}
202203

203204
type ControllerTypes = {

packages/devextreme/js/__internal/grids/tree_list/m_widget.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import TreeList from './m_widget_base';
44

55
import './m_state_storing';
6+
import './module_not_extended/ai_column_controller';
67
import './module_not_extended/column_chooser';
78
import './m_master_detail';
89
import './editing/m_editing';

packages/devextreme/js/__internal/grids/tree_list/m_widget_base.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const TREELIST_CLASS = 'dx-treelist';
2121
treeListCore.registerModulesOrder([
2222
'stateStoring',
2323
'columns',
24+
'aiColumn',
2425
'selection',
2526
'editorFactory',
2627
'columnChooser',

0 commit comments

Comments
 (0)