').appendTo(document.body);
+
+ const options: AIChatOptions = {
+ container: $container,
+ createComponent: createComponentMock as any,
+ ...optionsOverride,
+ };
+
+ const aiChat = new AIChat(options);
+
+ return { $container, aiChat };
+};
+
+const beforeTest = (): void => {
+ jest.clearAllMocks();
+};
+
+const afterTest = (): void => {
+ document.body.innerHTML = '';
+};
+
+describe('AIChat', () => {
+ beforeEach(beforeTest);
+ afterEach(afterTest);
+
+ describe('initialization', () => {
+ it('should add ai chat class to container', () => {
+ const { $container } = createAIChat();
+
+ expect($container.hasClass(CLASSES.aiChat)).toBe(true);
+ });
+
+ it('should create popup instance via createComponent', () => {
+ createAIChat();
+
+ expect(createComponentMock).toHaveBeenCalledTimes(1);
+ expect(createComponentMock).toHaveBeenCalledWith(
+ expect.any(Object),
+ Popup,
+ expect.objectContaining({
+ ...DEFAULT_POPUP_OPTIONS,
+ wrapperAttr: { class: `${CLASSES.aiChat} ${CLASSES.aiDialog}` },
+ contentTemplate: expect.any(Function),
+ }),
+ );
+ });
+ });
+
+ describe('show', () => {
+ it('should call popup show method', async () => {
+ const { aiChat } = createAIChat();
+
+ const result = await aiChat.show();
+
+ expect(mockPopupInstance.show).toHaveBeenCalledTimes(1);
+ expect(result).toBe(true);
+ });
+ });
+
+ describe('hide', () => {
+ it('should call popup hide method', async () => {
+ const { aiChat } = createAIChat();
+
+ const result = await aiChat.hide();
+
+ expect(mockPopupInstance.hide).toHaveBeenCalledTimes(1);
+ expect(result).toBe(true);
+ });
+ });
+});
From e7d00da986e531f729910cb20e28e14e62943a06 Mon Sep 17 00:00:00 2001
From: Alyar <>
Date: Wed, 1 Apr 2026 18:40:58 +0400
Subject: [PATCH 4/8] Fix themebuilder tests
---
packages/devextreme-themebuilder/tests/data/dependencies.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/packages/devextreme-themebuilder/tests/data/dependencies.ts b/packages/devextreme-themebuilder/tests/data/dependencies.ts
index 8e1319ccd981..634355fcd57b 100644
--- a/packages/devextreme-themebuilder/tests/data/dependencies.ts
+++ b/packages/devextreme-themebuilder/tests/data/dependencies.ts
@@ -57,11 +57,11 @@ export const dependencies: FlatStylesDependencies = {
treeview: ['validation', 'button', 'loadindicator', 'textbox', 'checkbox'],
menu: ['validation', 'button', 'loadindicator', 'textbox', 'contextmenu', 'checkbox', 'treeview'],
filterbuilder: ['validation', 'button', 'loadindicator', 'textbox', 'checkbox', 'treeview', 'popup', 'numberbox', 'loadpanel', 'scrollview', 'list', 'selectbox', 'calendar', 'box', 'datebox'],
- datagrid: ['loadindicator', 'loadpanel', 'validation', 'button', 'textbox', 'toast', 'contextmenu', 'scrollview', 'popup', 'progressbar', 'toolbar', 'checkbox', 'treeview', 'numberbox', 'list', 'selectbox', 'calendar', 'box', 'datebox', 'multiview', 'tabs', 'tabpanel', 'responsivebox', 'form', 'menu', 'filterbuilder', 'buttongroup', 'dropdownbutton', 'sortable', 'textarea'],
+ datagrid: ['loadindicator', 'loadpanel', 'validation', 'button', 'textbox', 'toast', 'contextmenu', 'scrollview', 'popup', 'progressbar', 'toolbar', 'checkbox', 'treeview', 'numberbox', 'list', 'selectbox', 'calendar', 'box', 'datebox', 'multiview', 'tabs', 'tabpanel', 'responsivebox', 'form', 'menu', 'filterbuilder', 'buttongroup', 'dropdownbutton', 'sortable', 'textarea', 'chat', 'speechtotext'],
treelist: ['loadindicator', 'loadpanel', 'validation', 'button', 'textbox', 'contextmenu', 'scrollview', 'popup', 'toolbar'],
pivotgrid: ['validation', 'button', 'loadindicator', 'textbox', 'contextmenu', 'popup', 'loadpanel', 'checkbox', 'treeview', 'scrollview', 'list'],
scheduler: ['validation', 'button', 'popup', 'loadindicator', 'loadpanel', 'multiview', 'tabs', 'tabpanel', 'box', 'responsivebox', 'textbox', 'numberbox', 'checkbox', 'calendar', 'scrollview', 'list', 'selectbox', 'datebox', 'form', 'buttongroup', 'radiogroup', 'textarea', 'tagbox', 'switch', 'dropdownbutton', 'popover', 'tooltip', 'toolbar'],
- filemanager: ['toast', 'validation', 'button', 'loadindicator', 'textbox', 'contextmenu', 'checkbox', 'treeview', 'loadpanel', 'scrollview', 'popup', 'toolbar', 'numberbox', 'list', 'selectbox', 'calendar', 'box', 'datebox', 'multiview', 'tabs', 'tabpanel', 'responsivebox', 'form', 'menu', 'filterbuilder', 'buttongroup', 'dropdownbutton', 'sortable', 'datagrid', 'drawer', 'progressbar', 'fileuploader', 'textarea'],
+ filemanager: ['toast', 'validation', 'button', 'loadindicator', 'textbox', 'contextmenu', 'checkbox', 'treeview', 'loadpanel', 'scrollview', 'popup', 'toolbar', 'numberbox', 'list', 'selectbox', 'calendar', 'box', 'datebox', 'multiview', 'tabs', 'tabpanel', 'responsivebox', 'form', 'menu', 'filterbuilder', 'buttongroup', 'dropdownbutton', 'sortable', 'datagrid', 'drawer', 'progressbar', 'fileuploader', 'textarea', 'chat', 'speechtotext'],
diagram: ['loadindicator', 'validation', 'button', 'loadpanel', 'scrollview', 'popup', 'toolbar', 'textbox', 'contextmenu', 'list', 'checkbox', 'selectbox', 'numberbox', 'colorbox', 'popover', 'accordion', 'tooltip', 'multiview', 'tabs', 'tabpanel', 'progressbar', 'fileuploader'],
- gantt: ['loadindicator', 'loadpanel', 'validation', 'button', 'popup', 'multiview', 'tabs', 'tabpanel', 'box', 'responsivebox', 'textbox', 'toast', 'numberbox', 'checkbox', 'calendar', 'scrollview', 'list', 'selectbox', 'datebox', 'form', 'tagbox', 'radiogroup', 'popover', 'actionsheet', 'toolbar', 'contextmenu', 'treeview', 'menu', 'filterbuilder', 'sortable', 'treelist', 'progressbar', 'textarea', 'buttongroup', 'dropdownbutton'],
+ gantt: ['loadindicator', 'loadpanel', 'validation', 'button', 'popup', 'multiview', 'tabs', 'tabpanel', 'box', 'responsivebox', 'textbox', 'toast', 'numberbox', 'checkbox', 'calendar', 'scrollview', 'list', 'selectbox', 'datebox', 'form', 'tagbox', 'radiogroup', 'popover', 'actionsheet', 'toolbar', 'contextmenu', 'treeview', 'menu', 'filterbuilder', 'sortable', 'treelist', 'progressbar', 'textarea', 'buttongroup', 'dropdownbutton', 'chat', 'speechtotext'],
};
From 5ed6170d738aa56aa59009caf13ee121821f2728 Mon Sep 17 00:00:00 2001
From: Alyar <>
Date: Wed, 1 Apr 2026 18:59:22 +0400
Subject: [PATCH 5/8] Fix copilot comments
---
.../devextreme/js/__internal/grids/data_grid/m_widget_base.ts | 1 -
.../grids/grid_core/ai_assistant/m_ai_assistant_view.ts | 4 ++--
.../devextreme/js/__internal/grids/grid_core/ai_chat/const.ts | 2 +-
3 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/packages/devextreme/js/__internal/grids/data_grid/m_widget_base.ts b/packages/devextreme/js/__internal/grids/data_grid/m_widget_base.ts
index 3a2726af2e44..1710af383abd 100644
--- a/packages/devextreme/js/__internal/grids/data_grid/m_widget_base.ts
+++ b/packages/devextreme/js/__internal/grids/data_grid/m_widget_base.ts
@@ -131,7 +131,6 @@ class DataGrid extends GridCoreWidget
{
gridCoreUtils.logHeaderFilterDeprecatedWarningIfNeed(that);
// @ts-expect-error
-
gridCore.processModules(that, gridCore as any);
gridCore.callModuleItemsMethod(that, 'init');
diff --git a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.ts b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.ts
index b00ec2a881ef..c0a9b6a4b29c 100644
--- a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.ts
+++ b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.ts
@@ -5,7 +5,7 @@ import { View } from '../m_modules';
export class AIAssistantView extends View {
private aiChatInstance!: AIChat;
- private getAIPromptEditorConfig(): AIChatOptions {
+ private getAIChatConfig(): AIChatOptions {
return {
container: this.element(),
createComponent: this._createComponent.bind(this),
@@ -13,7 +13,7 @@ export class AIAssistantView extends View {
}
protected _renderCore(): void {
- const config = this.getAIPromptEditorConfig();
+ const config = this.getAIChatConfig();
if (!this.aiChatInstance) {
this.aiChatInstance = new AIChat(config);
diff --git a/packages/devextreme/js/__internal/grids/grid_core/ai_chat/const.ts b/packages/devextreme/js/__internal/grids/grid_core/ai_chat/const.ts
index 14657ab88fd8..b775aa9570c5 100644
--- a/packages/devextreme/js/__internal/grids/grid_core/ai_chat/const.ts
+++ b/packages/devextreme/js/__internal/grids/grid_core/ai_chat/const.ts
@@ -6,6 +6,6 @@ export const DEFAULT_POPUP_OPTIONS = {
export const CLASSES = {
aiChat: 'dx-ai-chat',
- aiDialog: 'dx-ai-dialog',
+ aiDialog: 'dx-aidialog',
aiChatContent: 'dx-ai-chat__content',
};
From f4437d0acef9fe48145305aa26957726a5476b59 Mon Sep 17 00:00:00 2001
From: Alyar <>
Date: Wed, 1 Apr 2026 21:39:04 +0400
Subject: [PATCH 6/8] feat: add aiAssistant visibility to AIAssistantView
---
.../ai_assistant/m_ai_assistant_view.test.ts | 79 +++++++++++++++----
.../ai_assistant/m_ai_assistant_view.ts | 4 +
2 files changed, 66 insertions(+), 17 deletions(-)
diff --git a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.test.ts b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.test.ts
index ee2a760690d5..92a7c8afd9cb 100644
--- a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.test.ts
+++ b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.test.ts
@@ -33,21 +33,47 @@ const createComponentMock = jest.fn((
options: any,
): any => new Widget(el, options));
-const createAIAssistantView = (): {
+const createAIAssistantView = ({
+ initialVisible = true,
+ render = true,
+}: {
+ initialVisible?: boolean;
+ render?: boolean;
+} = {}): {
$container: dxElementWrapper;
aiAssistantView: AIAssistantView;
+ optionMock: jest.Mock<(name: string) => boolean | undefined>;
+ setVisible: (value: boolean) => void;
} => {
const $container = $('').appendTo(document.body);
+ let isVisible = initialVisible;
+ const optionMock = jest.fn((name: string): boolean | undefined => {
+ if (name === 'aiAssistant.visible') {
+ return isVisible;
+ }
+
+ return undefined;
+ });
const mockComponent = {
element: (): any => $container.get(0),
_createComponent: createComponentMock,
_controllers: {},
+ option: optionMock,
};
const aiAssistantView = new AIAssistantView(mockComponent);
- aiAssistantView.render($container);
+ if (render) {
+ aiAssistantView.render($container);
+ }
- return { $container, aiAssistantView };
+ return {
+ $container,
+ aiAssistantView,
+ optionMock,
+ setVisible: (value: boolean) => {
+ isVisible = value;
+ },
+ };
};
const beforeTest = (): void => {
@@ -66,6 +92,20 @@ describe('AIAssistantView', () => {
beforeEach(beforeTest);
afterEach(afterTest);
+ describe('isVisible', () => {
+ it('should return aiAssistant.visible option value', () => {
+ const { aiAssistantView, optionMock, setVisible } = createAIAssistantView({ render: false });
+
+ expect(aiAssistantView.isVisible()).toBe(true);
+
+ setVisible(false);
+
+ expect(aiAssistantView.isVisible()).toBe(false);
+ expect(optionMock).toHaveBeenNthCalledWith(1, 'aiAssistant.visible');
+ expect(optionMock).toHaveBeenNthCalledWith(2, 'aiAssistant.visible');
+ });
+ });
+
describe('initialization', () => {
it('should create AIChat instance on first render', () => {
createAIAssistantView();
@@ -91,6 +131,23 @@ describe('AIAssistantView', () => {
expect(AIChat).toHaveBeenCalledTimes(1);
});
+
+ it('should not create AIChat instance when view is hidden', () => {
+ const { aiAssistantView } = createAIAssistantView({ initialVisible: false });
+
+ expect(AIChat).not.toHaveBeenCalled();
+ expect(aiAssistantView.element().hasClass('dx-hidden')).toBe(true);
+ });
+
+ it('should create AIChat instance when view becomes visible', () => {
+ const { $container, aiAssistantView, setVisible } = createAIAssistantView({ initialVisible: false });
+
+ setVisible(true);
+ aiAssistantView.render($container);
+
+ expect(AIChat).toHaveBeenCalledTimes(1);
+ expect(aiAssistantView.element().hasClass('dx-hidden')).toBe(false);
+ });
});
describe('show', () => {
@@ -121,13 +178,7 @@ describe('AIAssistantView', () => {
describe('show when not initialized', () => {
it('should return resolved false promise when aiChatInstance is not created', () => {
- const mockComponent = {
- element: (): any => $('
').get(0),
- _createComponent: createComponentMock,
- _controllers: {},
- };
-
- const aiAssistantView = new AIAssistantView(mockComponent);
+ const { aiAssistantView } = createAIAssistantView({ render: false });
return expect(aiAssistantView.show()).resolves.toBe(false);
});
@@ -135,13 +186,7 @@ describe('AIAssistantView', () => {
describe('hide when not initialized', () => {
it('should return resolved false promise when aiChatInstance is not created', () => {
- const mockComponent = {
- element: (): any => $('
').get(0),
- _createComponent: createComponentMock,
- _controllers: {},
- };
-
- const aiAssistantView = new AIAssistantView(mockComponent);
+ const { aiAssistantView } = createAIAssistantView({ render: false });
return expect(aiAssistantView.hide()).resolves.toBe(false);
});
diff --git a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.ts b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.ts
index c0a9b6a4b29c..c7af649400ed 100644
--- a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.ts
+++ b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.ts
@@ -20,6 +20,10 @@ export class AIAssistantView extends View {
}
}
+ public isVisible(): boolean {
+ return this.option('aiAssistant.visible');
+ }
+
public show(): Promise
{
return this.aiChatInstance?.show() ?? Promise.resolve(false);
}
From 33a10f95a5de07c8e1203c227ff67266ddb0695b Mon Sep 17 00:00:00 2001
From: Alyar <>
Date: Thu, 2 Apr 2026 12:03:49 +0400
Subject: [PATCH 7/8] fix: use aiAssistant enabled option in AIAssistantView
---
.../grids/grid_core/ai_assistant/m_ai_assistant_view.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.ts b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.ts
index c7af649400ed..4e19e58f0425 100644
--- a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.ts
+++ b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.ts
@@ -21,7 +21,7 @@ export class AIAssistantView extends View {
}
public isVisible(): boolean {
- return this.option('aiAssistant.visible');
+ return this.option('aiAssistant.enabled');
}
public show(): Promise {
From 122434ac113293fb680c218302a6a106ea7433fd Mon Sep 17 00:00:00 2001
From: Alyar <>
Date: Thu, 2 Apr 2026 13:24:33 +0400
Subject: [PATCH 8/8] Fix jest tests
---
.../ai_assistant/m_ai_assistant_view.test.ts | 38 ++++++++++---------
1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.test.ts b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.test.ts
index 92a7c8afd9cb..1ea0905daaaf 100644
--- a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.test.ts
+++ b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.test.ts
@@ -34,22 +34,22 @@ const createComponentMock = jest.fn((
): any => new Widget(el, options));
const createAIAssistantView = ({
- initialVisible = true,
+ initialEnabled = true,
render = true,
}: {
- initialVisible?: boolean;
+ initialEnabled?: boolean;
render?: boolean;
} = {}): {
$container: dxElementWrapper;
aiAssistantView: AIAssistantView;
optionMock: jest.Mock<(name: string) => boolean | undefined>;
- setVisible: (value: boolean) => void;
+ setEnabled: (value: boolean) => void;
} => {
const $container = $('').appendTo(document.body);
- let isVisible = initialVisible;
+ let isEnabled = initialEnabled;
const optionMock = jest.fn((name: string): boolean | undefined => {
- if (name === 'aiAssistant.visible') {
- return isVisible;
+ if (name === 'aiAssistant.enabled') {
+ return isEnabled;
}
return undefined;
@@ -70,8 +70,8 @@ const createAIAssistantView = ({
$container,
aiAssistantView,
optionMock,
- setVisible: (value: boolean) => {
- isVisible = value;
+ setEnabled: (value: boolean): void => {
+ isEnabled = value;
},
};
};
@@ -93,16 +93,16 @@ describe('AIAssistantView', () => {
afterEach(afterTest);
describe('isVisible', () => {
- it('should return aiAssistant.visible option value', () => {
- const { aiAssistantView, optionMock, setVisible } = createAIAssistantView({ render: false });
+ it('should return aiAssistant.enabled option value', () => {
+ const { aiAssistantView, optionMock, setEnabled } = createAIAssistantView({ render: false });
expect(aiAssistantView.isVisible()).toBe(true);
- setVisible(false);
+ setEnabled(false);
expect(aiAssistantView.isVisible()).toBe(false);
- expect(optionMock).toHaveBeenNthCalledWith(1, 'aiAssistant.visible');
- expect(optionMock).toHaveBeenNthCalledWith(2, 'aiAssistant.visible');
+ expect(optionMock).toHaveBeenNthCalledWith(1, 'aiAssistant.enabled');
+ expect(optionMock).toHaveBeenNthCalledWith(2, 'aiAssistant.enabled');
});
});
@@ -132,17 +132,19 @@ describe('AIAssistantView', () => {
expect(AIChat).toHaveBeenCalledTimes(1);
});
- it('should not create AIChat instance when view is hidden', () => {
- const { aiAssistantView } = createAIAssistantView({ initialVisible: false });
+ it('should not create AIChat instance when aiAssistant is disabled', () => {
+ const { aiAssistantView } = createAIAssistantView({ initialEnabled: false });
expect(AIChat).not.toHaveBeenCalled();
expect(aiAssistantView.element().hasClass('dx-hidden')).toBe(true);
});
- it('should create AIChat instance when view becomes visible', () => {
- const { $container, aiAssistantView, setVisible } = createAIAssistantView({ initialVisible: false });
+ it('should create AIChat instance when aiAssistant becomes enabled', () => {
+ const { $container, aiAssistantView, setEnabled } = createAIAssistantView({
+ initialEnabled: false,
+ });
- setVisible(true);
+ setEnabled(true);
aiAssistantView.render($container);
expect(AIChat).toHaveBeenCalledTimes(1);