Skip to content

Commit 2eb2598

Browse files
authored
DataGrid - AI Column: Support for sticky columns (#31150)
Co-authored-by: Alyar <>
1 parent 6f23e5b commit 2eb2598

File tree

6 files changed

+303
-0
lines changed

6 files changed

+303
-0
lines changed
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import DataGrid from 'devextreme-testcafe-models/dataGrid';
2+
import url from '../../../../helpers/getPageUrl';
3+
import { createWidget } from '../../../../helpers/createWidget';
4+
5+
fixture.disablePageReloads`Ai Column - Sticky columns.Functional`
6+
.page(url(__dirname, '../../../container.html'));
7+
8+
const DATA_GRID_SELECTOR = '#container';
9+
10+
test('The AI column should not be fixed when the columnFixing.enabled option is true', async (t) => {
11+
// arrange, act
12+
const dataGrid = new DataGrid(DATA_GRID_SELECTOR);
13+
14+
await t.expect(dataGrid.isReady()).ok();
15+
16+
const aiHeader = dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(3);
17+
18+
// assert
19+
await t.expect(aiHeader.element.textContent).eql('AI Column');
20+
await t.expect(aiHeader.isSticky()).notOk();
21+
}).before(async () => createWidget('dxDataGrid', {
22+
dataSource: [
23+
{ id: 1, name: 'Name 1', value: 10 },
24+
{ id: 2, name: 'Name 2', value: 20 },
25+
{ id: 3, name: 'Name 3', value: 30 },
26+
],
27+
width: 600,
28+
columnWidth: 200,
29+
columnFixing: {
30+
enabled: true,
31+
},
32+
columns: [
33+
{ dataField: 'id', caption: 'ID' },
34+
{ dataField: 'name', caption: 'Name' },
35+
{ dataField: 'value', caption: 'Value' },
36+
{
37+
type: 'ai',
38+
caption: 'AI Column',
39+
name: 'myAiColumn',
40+
},
41+
],
42+
}));
43+
44+
test('The AI column should be fixed when its fixed option is true', async (t) => {
45+
// arrange, act
46+
const dataGrid = new DataGrid(DATA_GRID_SELECTOR);
47+
48+
await t.expect(dataGrid.isReady()).ok();
49+
50+
const aiHeader = dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(0);
51+
52+
// assert
53+
await t.expect(aiHeader.element.textContent).eql('AI Column');
54+
await t.expect(aiHeader.isSticky('left')).ok();
55+
}).before(async () => createWidget('dxDataGrid', {
56+
dataSource: [
57+
{ id: 1, name: 'Name 1', value: 10 },
58+
{ id: 2, name: 'Name 2', value: 20 },
59+
{ id: 3, name: 'Name 3', value: 30 },
60+
],
61+
width: 600,
62+
columnWidth: 200,
63+
columns: [
64+
{ dataField: 'id', caption: 'ID' },
65+
{ dataField: 'name', caption: 'Name' },
66+
{ dataField: 'value', caption: 'Value' },
67+
{
68+
type: 'ai',
69+
caption: 'AI Column',
70+
fixed: true,
71+
name: 'myAiColumn',
72+
},
73+
],
74+
}));
75+
76+
test('The AI column should be fixed when its fixed option is true and its fixed position is set to right', async (t) => {
77+
// arrange, act
78+
const dataGrid = new DataGrid(DATA_GRID_SELECTOR);
79+
80+
await t.expect(dataGrid.isReady()).ok();
81+
82+
const aiHeader = dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(3);
83+
84+
// assert
85+
await t.expect(aiHeader.element.textContent).eql('AI Column');
86+
await t.expect(aiHeader.isSticky('right')).ok();
87+
}).before(async () => createWidget('dxDataGrid', {
88+
dataSource: [
89+
{ id: 1, name: 'Name 1', value: 10 },
90+
{ id: 2, name: 'Name 2', value: 20 },
91+
{ id: 3, name: 'Name 3', value: 30 },
92+
],
93+
width: 600,
94+
columnWidth: 200,
95+
columns: [
96+
{ dataField: 'id', caption: 'ID' },
97+
{ dataField: 'name', caption: 'Name' },
98+
{ dataField: 'value', caption: 'Value' },
99+
{
100+
type: 'ai',
101+
caption: 'AI Column',
102+
fixed: true,
103+
fixedPosition: 'right',
104+
name: 'myAiColumn',
105+
},
106+
],
107+
}));
108+
109+
test('The AI column should be fixed when its fixed option is true and its fixed position is set to sticky', async (t) => {
110+
// arrange, act
111+
const dataGrid = new DataGrid(DATA_GRID_SELECTOR);
112+
113+
await t.expect(dataGrid.isReady()).ok();
114+
115+
const aiHeader = dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(1);
116+
117+
// assert
118+
await t.expect(aiHeader.element.textContent).eql('AI Column');
119+
await t.expect(aiHeader.isSticky('sticky')).ok();
120+
}).before(async () => createWidget('dxDataGrid', {
121+
dataSource: [
122+
{ id: 1, name: 'Name 1', value: 10 },
123+
{ id: 2, name: 'Name 2', value: 20 },
124+
{ id: 3, name: 'Name 3', value: 30 },
125+
],
126+
width: 600,
127+
columnWidth: 200,
128+
columns: [
129+
{ dataField: 'id', caption: 'ID' },
130+
{
131+
type: 'ai',
132+
caption: 'AI Column',
133+
fixed: true,
134+
fixedPosition: 'sticky',
135+
name: 'myAiColumn',
136+
},
137+
{ dataField: 'name', caption: 'Name' },
138+
{ dataField: 'value', caption: 'Value' },
139+
],
140+
}));
141+
142+
test('Fix an AI column using the context menu', async (t) => {
143+
// arrange
144+
const dataGrid = new DataGrid(DATA_GRID_SELECTOR);
145+
const contextMenu = dataGrid.getContextMenu();
146+
147+
await t.expect(dataGrid.isReady()).ok();
148+
149+
const aiHeader = dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(0);
150+
151+
// assert
152+
await t
153+
.expect(aiHeader.element.textContent).eql('AI Column')
154+
.expect(aiHeader.isSticky('left')).notOk();
155+
156+
// act
157+
await t
158+
.rightClick(aiHeader.element)
159+
.click(contextMenu.getItemByText('Set Fixed Position'))
160+
.click(contextMenu.getItemByText('Left'));
161+
162+
// assert
163+
await t.expect(aiHeader.element.textContent).eql('AI Column');
164+
await t.expect(aiHeader.isSticky('left')).ok();
165+
}).before(async () => createWidget('dxDataGrid', {
166+
dataSource: [
167+
{ id: 1, name: 'Name 1', value: 10 },
168+
{ id: 2, name: 'Name 2', value: 20 },
169+
{ id: 3, name: 'Name 3', value: 30 },
170+
],
171+
width: 600,
172+
columnWidth: 200,
173+
columnFixing: {
174+
enabled: true,
175+
},
176+
columns: [
177+
{
178+
type: 'ai',
179+
caption: 'AI Column',
180+
name: 'myAiColumn',
181+
},
182+
{ dataField: 'id', caption: 'ID' },
183+
{ dataField: 'name', caption: 'Name' },
184+
{ dataField: 'value', caption: 'Value' },
185+
],
186+
}));
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import DataGrid from 'devextreme-testcafe-models/dataGrid';
2+
import { createScreenshotsComparer } from 'devextreme-screenshot-comparer';
3+
import url from '../../../../helpers/getPageUrl';
4+
import { createWidget } from '../../../../helpers/createWidget';
5+
6+
fixture.disablePageReloads`Ai Column - Sticky columns.Visual`
7+
.page(url(__dirname, '../../../container.html'));
8+
9+
const DATA_GRID_SELECTOR = '#container';
10+
11+
test('Check context menu items', async (t) => {
12+
// arrange
13+
const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
14+
const dataGrid = new DataGrid(DATA_GRID_SELECTOR);
15+
16+
await t.expect(dataGrid.isReady()).ok();
17+
18+
// act
19+
await t
20+
.rightClick(dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(0).element)
21+
.click(dataGrid.getContextMenu().getItemByText('Set Fixed Position'));
22+
23+
await takeScreenshot('datagrid__ai-column-and-sticky-columns__context-menu.png', dataGrid.element);
24+
25+
// assert
26+
await t
27+
.expect(compareResults.isValid())
28+
.ok(compareResults.errorMessages());
29+
}).before(async () => createWidget('dxDataGrid', {
30+
dataSource: [
31+
{ id: 1, name: 'Name 1', value: 10 },
32+
{ id: 2, name: 'Name 2', value: 20 },
33+
{ id: 3, name: 'Name 3', value: 30 },
34+
],
35+
width: 600,
36+
columnWidth: 200,
37+
columnFixing: {
38+
enabled: true,
39+
},
40+
columns: [
41+
{
42+
type: 'ai',
43+
caption: 'AI Column',
44+
name: 'myAiColumn',
45+
},
46+
{ dataField: 'id', caption: 'ID' },
47+
{ dataField: 'name', caption: 'Name' },
48+
{ dataField: 'value', caption: 'Value' },
49+
],
50+
}));
51+
52+
test('Check context menu items when allowFixing is false', async (t) => {
53+
// arrange
54+
const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
55+
const dataGrid = new DataGrid(DATA_GRID_SELECTOR);
56+
57+
await t.expect(dataGrid.isReady()).ok();
58+
59+
// act
60+
await t.rightClick(dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(0).element);
61+
62+
await takeScreenshot('datagrid__ai-column-and-sticky-columns__context-menu-when-allowFixing-false.png', dataGrid.element);
63+
64+
// assert
65+
await t
66+
.expect(compareResults.isValid())
67+
.ok(compareResults.errorMessages());
68+
}).before(async () => createWidget('dxDataGrid', {
69+
dataSource: [
70+
{ id: 1, name: 'Name 1', value: 10 },
71+
{ id: 2, name: 'Name 2', value: 20 },
72+
{ id: 3, name: 'Name 3', value: 30 },
73+
],
74+
width: 600,
75+
columnWidth: 200,
76+
columnFixing: {
77+
enabled: true,
78+
},
79+
columns: [
80+
{
81+
type: 'ai',
82+
caption: 'AI Column',
83+
allowFixing: false,
84+
name: 'myAiColumn',
85+
},
86+
{ dataField: 'id', caption: 'ID' },
87+
{ dataField: 'name', caption: 'Name' },
88+
{ dataField: 'value', caption: 'Value' },
89+
],
90+
}));
Loading
13.1 KB
Loading

packages/devextreme/js/__internal/grids/grid_core/ai_column/m_ai_column_controller_utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export const getAiCommandColumnOptions = () => ({
44
type: AI_COLUMN_NAME,
55
command: AI_COLUMN_NAME,
66
cssClass: CLASSES.aiColumn,
7+
fixed: false,
78
});

packages/testcafe-models/dataGrid/headers/cell.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,31 @@ import { ClientFunction, Selector } from 'testcafe';
22
import FocusableElement from '../../internal/focusable';
33
import Widget from '../../internal/widget';
44

5+
type StickyPosition = 'left' | 'right' | 'sticky';
6+
57
const CLASS = {
68
hiddenColumn: 'hidden-column',
79
filterMenu: 'dx-header-filter-menu',
810
list: 'dx-list',
911
stateHover: 'dx-state-hover',
12+
sticky: 'dx-datagrid-sticky-column',
13+
stickyLeft: 'dx-datagrid-sticky-column-left',
14+
stickyRight: 'dx-datagrid-sticky-column-right',
1015
};
1116

17+
const getStickyClassNames = (position: StickyPosition | undefined): string[] => {
18+
switch (position) {
19+
case 'left':
20+
return [CLASS.stickyLeft];
21+
case 'right':
22+
return [CLASS.stickyRight];
23+
case 'sticky':
24+
return [CLASS.sticky];
25+
default:
26+
return [CLASS.sticky, CLASS.stickyLeft, CLASS.stickyRight];
27+
}
28+
}
29+
1230
export default class HeaderCell {
1331
element: Selector;
1432

@@ -18,6 +36,14 @@ export default class HeaderCell {
1836

1937
isHidden: Promise<boolean>;
2038

39+
isSticky(position?: StickyPosition | undefined): Promise<boolean> {
40+
return ClientFunction((element, stickyClassNames) => {
41+
const elementClassList = element().classList;
42+
43+
return stickyClassNames.some((className) => elementClassList.contains(className));
44+
})(this.element, getStickyClassNames(position));
45+
};
46+
2147
isHovered(): Promise<boolean> {
2248
return ClientFunction((element) => {
2349
return element() === document.querySelector("td:hover");

0 commit comments

Comments
 (0)