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'], }; diff --git a/packages/devextreme/js/__internal/grids/data_grid/m_widget.ts b/packages/devextreme/js/__internal/grids/data_grid/m_widget.ts index 6db581e934f1..c4aae3a92e8a 100644 --- a/packages/devextreme/js/__internal/grids/data_grid/m_widget.ts +++ b/packages/devextreme/js/__internal/grids/data_grid/m_widget.ts @@ -34,5 +34,6 @@ import './export/m_export'; import './focus/m_focus'; import './module_not_extended/row_dragging'; import './module_not_extended/toast'; +import './module_not_extended/ai_assistant'; export default DataGrid; 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 1f89a28c8262..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 @@ -43,6 +43,7 @@ gridCore.registerModulesOrder([ 'columnHeaders', 'filterRow', 'headerPanel', + 'aiAssistant', 'headerFilter', 'sorting', 'search', @@ -130,7 +131,6 @@ class DataGrid extends GridCoreWidget { gridCoreUtils.logHeaderFilterDeprecatedWarningIfNeed(that); // @ts-expect-error - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion gridCore.processModules(that, gridCore as any); gridCore.callModuleItemsMethod(that, 'init'); diff --git a/packages/devextreme/js/__internal/grids/data_grid/module_not_extended/ai_assistant.ts b/packages/devextreme/js/__internal/grids/data_grid/module_not_extended/ai_assistant.ts new file mode 100644 index 000000000000..d17168f3e673 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/data_grid/module_not_extended/ai_assistant.ts @@ -0,0 +1,13 @@ +import { AIAssistantView } from '@ts/grids/grid_core/ai_assistant/m_ai_assistant_view'; +import { AIAssistantViewController } from '@ts/grids/grid_core/ai_assistant/m_ai_assistant_view_controller'; + +import gridCore from '../m_core'; + +gridCore.registerModule('aiAssistant', { + controllers: { + aiAssistant: AIAssistantViewController, + }, + views: { + aiAssistantView: AIAssistantView, + }, +}); 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 new file mode 100644 index 000000000000..1ea0905daaaf --- /dev/null +++ b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.test.ts @@ -0,0 +1,196 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { + afterEach, + beforeEach, + describe, + expect, + it, + jest, +} from '@jest/globals'; +import fx from '@js/common/core/animation/fx'; +import type { dxElementWrapper } from '@js/core/renderer'; +import $ from '@js/core/renderer'; +import wrapInstanceWithMocks from '@ts/grids/grid_core/__tests__/__mock__/helpers/wrapInstance'; + +import { AIChat } from '../ai_chat/ai_chat'; +import { AIAssistantView } from './m_ai_assistant_view'; + +jest.mock('../ai_chat/ai_chat', (): any => { + const original = jest.requireActual('../ai_chat/ai_chat'); + + return { + ...original, + AIChat: jest.fn((...args: any[]) => { + const instance: AIChat = new original.AIChat(...args); + return wrapInstanceWithMocks(instance); + }), + }; +}); + +const createComponentMock = jest.fn(( + el: dxElementWrapper, + Widget: any, + options: any, +): any => new Widget(el, options)); + +const createAIAssistantView = ({ + initialEnabled = true, + render = true, +}: { + initialEnabled?: boolean; + render?: boolean; +} = {}): { + $container: dxElementWrapper; + aiAssistantView: AIAssistantView; + optionMock: jest.Mock<(name: string) => boolean | undefined>; + setEnabled: (value: boolean) => void; +} => { + const $container = $('
').appendTo(document.body); + let isEnabled = initialEnabled; + const optionMock = jest.fn((name: string): boolean | undefined => { + if (name === 'aiAssistant.enabled') { + return isEnabled; + } + + return undefined; + }); + const mockComponent = { + element: (): any => $container.get(0), + _createComponent: createComponentMock, + _controllers: {}, + option: optionMock, + }; + + const aiAssistantView = new AIAssistantView(mockComponent); + if (render) { + aiAssistantView.render($container); + } + + return { + $container, + aiAssistantView, + optionMock, + setEnabled: (value: boolean): void => { + isEnabled = value; + }, + }; +}; + +const beforeTest = (): void => { + fx.off = true; + jest.useFakeTimers(); + jest.clearAllMocks(); +}; + +const afterTest = (): void => { + document.body.innerHTML = ''; + fx.off = false; + jest.useRealTimers(); +}; + +describe('AIAssistantView', () => { + beforeEach(beforeTest); + afterEach(afterTest); + + describe('isVisible', () => { + it('should return aiAssistant.enabled option value', () => { + const { aiAssistantView, optionMock, setEnabled } = createAIAssistantView({ render: false }); + + expect(aiAssistantView.isVisible()).toBe(true); + + setEnabled(false); + + expect(aiAssistantView.isVisible()).toBe(false); + expect(optionMock).toHaveBeenNthCalledWith(1, 'aiAssistant.enabled'); + expect(optionMock).toHaveBeenNthCalledWith(2, 'aiAssistant.enabled'); + }); + }); + + describe('initialization', () => { + it('should create AIChat instance on first render', () => { + createAIAssistantView(); + + expect(AIChat).toHaveBeenCalledTimes(1); + }); + + it('should pass container and createComponent to AIChat', () => { + const { aiAssistantView } = createAIAssistantView(); + + expect(AIChat).toHaveBeenCalledWith( + expect.objectContaining({ + container: aiAssistantView.element(), + createComponent: expect.any(Function), + }), + ); + }); + + it('should not create a new AIChat instance on subsequent renders', () => { + const { $container, aiAssistantView } = createAIAssistantView(); + + aiAssistantView.render($container); + + expect(AIChat).toHaveBeenCalledTimes(1); + }); + + 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 aiAssistant becomes enabled', () => { + const { $container, aiAssistantView, setEnabled } = createAIAssistantView({ + initialEnabled: false, + }); + + setEnabled(true); + aiAssistantView.render($container); + + expect(AIChat).toHaveBeenCalledTimes(1); + expect(aiAssistantView.element().hasClass('dx-hidden')).toBe(false); + }); + }); + + describe('show', () => { + it('should delegate to AIChat show method', async () => { + const { aiAssistantView } = createAIAssistantView(); + + await aiAssistantView.show(); + + const aiChatInstance = (AIChat as jest.Mock) + .mock.results[0].value as { show: jest.Mock; hide: jest.Mock }; + + expect(aiChatInstance.show).toHaveBeenCalledTimes(1); + }); + }); + + describe('hide', () => { + it('should delegate to AIChat hide method', async () => { + const { aiAssistantView } = createAIAssistantView(); + + await aiAssistantView.hide(); + + const aiChatInstance = (AIChat as jest.Mock) + .mock.results[0].value as { show: jest.Mock; hide: jest.Mock }; + + expect(aiChatInstance.hide).toHaveBeenCalledTimes(1); + }); + }); + + describe('show when not initialized', () => { + it('should return resolved false promise when aiChatInstance is not created', () => { + const { aiAssistantView } = createAIAssistantView({ render: false }); + + return expect(aiAssistantView.show()).resolves.toBe(false); + }); + }); + + describe('hide when not initialized', () => { + it('should return resolved false promise when aiChatInstance is not created', () => { + 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 new file mode 100644 index 000000000000..4e19e58f0425 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view.ts @@ -0,0 +1,34 @@ +import { AIChat } from '../ai_chat/ai_chat'; +import type { AIChatOptions } from '../ai_chat/types'; +import { View } from '../m_modules'; + +export class AIAssistantView extends View { + private aiChatInstance!: AIChat; + + private getAIChatConfig(): AIChatOptions { + return { + container: this.element(), + createComponent: this._createComponent.bind(this), + }; + } + + protected _renderCore(): void { + const config = this.getAIChatConfig(); + + if (!this.aiChatInstance) { + this.aiChatInstance = new AIChat(config); + } + } + + public isVisible(): boolean { + return this.option('aiAssistant.enabled'); + } + + public show(): Promise { + return this.aiChatInstance?.show() ?? Promise.resolve(false); + } + + public hide(): Promise { + return this.aiChatInstance?.hide() ?? Promise.resolve(false); + } +} diff --git a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view_controller.test.ts b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view_controller.test.ts new file mode 100644 index 000000000000..1dcb7d198766 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view_controller.test.ts @@ -0,0 +1,79 @@ +import { + afterEach, + beforeEach, + describe, + expect, + it, + jest, +} from '@jest/globals'; + +import { AIAssistantViewController } from './m_ai_assistant_view_controller'; + +interface MockAIAssistantView { + show: jest.Mock<() => Promise>; + hide: jest.Mock<() => Promise>; +} + +const createMockAIAssistantView = (): MockAIAssistantView => ({ + show: jest.fn<() => Promise>().mockResolvedValue(true), + hide: jest.fn<() => Promise>().mockResolvedValue(true), +}); + +const createAIAssistantViewController = (): { + controller: AIAssistantViewController; + mockView: ReturnType; +} => { + const mockView = createMockAIAssistantView(); + const mockComponent = { + _views: { + aiAssistantView: mockView, + }, + _controllers: {}, + }; + + const controller = new AIAssistantViewController(mockComponent); + controller.init(); + + return { controller, mockView }; +}; + +const beforeTest = (): void => { + jest.clearAllMocks(); +}; + +describe('AIAssistantViewController', () => { + beforeEach(beforeTest); + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('init', () => { + it('should get aiAssistantView reference', () => { + const { controller } = createAIAssistantViewController(); + + expect(controller).toBeDefined(); + }); + }); + + describe('show', () => { + it('should delegate to aiAssistantView show method', async () => { + const { controller, mockView } = createAIAssistantViewController(); + + const result = await controller.show(); + + expect(mockView.show).toHaveBeenCalledTimes(1); + expect(result).toBe(true); + }); + }); + + describe('hide', () => { + it('should delegate to aiAssistantView hide method', async () => { + const { controller, mockView } = createAIAssistantViewController(); + + const result = await controller.hide(); + + expect(mockView.hide).toHaveBeenCalledTimes(1); + expect(result).toBe(true); + }); + }); +}); diff --git a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view_controller.ts b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view_controller.ts new file mode 100644 index 000000000000..dfb0e345b13b --- /dev/null +++ b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/m_ai_assistant_view_controller.ts @@ -0,0 +1,18 @@ +import { ViewController } from '../m_modules'; +import type { AIAssistantView } from './m_ai_assistant_view'; + +export class AIAssistantViewController extends ViewController { + private aiAssistantView!: AIAssistantView; + + public init(): void { + this.aiAssistantView = this.getView('aiAssistantView'); + } + + public show(): Promise { + return this.aiAssistantView.show(); + } + + public hide(): Promise { + return this.aiAssistantView.hide(); + } +} diff --git a/packages/devextreme/js/__internal/grids/grid_core/ai_chat/ai_chat.test.ts b/packages/devextreme/js/__internal/grids/grid_core/ai_chat/ai_chat.test.ts new file mode 100644 index 000000000000..319dc494630f --- /dev/null +++ b/packages/devextreme/js/__internal/grids/grid_core/ai_chat/ai_chat.test.ts @@ -0,0 +1,111 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { + afterEach, + beforeEach, + describe, + expect, + it, + jest, +} from '@jest/globals'; +import $ from '@js/core/renderer'; +import Chat from '@js/ui/chat'; +import Popup from '@js/ui/popup'; + +import { AIChat } from './ai_chat'; +import { CLASSES, DEFAULT_POPUP_OPTIONS } from './const'; +import type { AIChatOptions } from './types'; + +const mockPopupInstance = { + show: jest.fn<() => Promise>().mockResolvedValue(true), + hide: jest.fn<() => Promise>().mockResolvedValue(true), +}; + +const mockChatInstance = {}; + +const createComponentMock = jest.fn(( + _el: any, + Widget: any, +): any => { + if (Widget === Popup) { + return mockPopupInstance; + } + if (Widget === Chat) { + return mockChatInstance; + } + return {}; +}); + +const createAIChat = (optionsOverride: Partial = {}): { + $container: ReturnType; + aiChat: AIChat; +} => { + const $container = $('
').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); + }); + }); +}); diff --git a/packages/devextreme/js/__internal/grids/grid_core/ai_chat/ai_chat.ts b/packages/devextreme/js/__internal/grids/grid_core/ai_chat/ai_chat.ts new file mode 100644 index 000000000000..0705555bcf12 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/grid_core/ai_chat/ai_chat.ts @@ -0,0 +1,53 @@ +import $ from '@js/core/renderer'; +import type { Properties as ChatProperties } from '@js/ui/chat'; +import Chat from '@js/ui/chat'; +import type { Properties as PopupProperties } from '@js/ui/popup'; +import Popup from '@js/ui/popup'; + +import { CLASSES, DEFAULT_POPUP_OPTIONS } from './const'; +import type { AIChatOptions } from './types'; + +export class AIChat { + private readonly popupInstance: Popup; + + private chatInstance!: Chat; + + constructor( + private readonly options: AIChatOptions, + ) { + const { container, createComponent } = options; + + container.addClass(CLASSES.aiChat); + this.popupInstance = createComponent(container, Popup, this.getPopupConfig()); + } + + private getChatConfig(): ChatProperties { + return {}; + } + + private getPopupConfig(): PopupProperties { + return { + ...DEFAULT_POPUP_OPTIONS, + wrapperAttr: { class: `${CLASSES.aiChat} ${CLASSES.aiDialog}` }, + contentTemplate: ($container): void => { + const $editorContainer = $('
') + .addClass(CLASSES.aiChatContent) + .appendTo($container); + + this.chatInstance = this.options.createComponent( + $editorContainer, + Chat, + this.getChatConfig(), + ); + }, + }; + } + + public show(): Promise { + return this.popupInstance.show(); + } + + public hide(): Promise { + return this.popupInstance.hide(); + } +} 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 new file mode 100644 index 000000000000..b775aa9570c5 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/grid_core/ai_chat/const.ts @@ -0,0 +1,11 @@ +export const DEFAULT_POPUP_OPTIONS = { + width: 360, + height: 'auto', + visible: false, +}; + +export const CLASSES = { + aiChat: 'dx-ai-chat', + aiDialog: 'dx-aidialog', + aiChatContent: 'dx-ai-chat__content', +}; diff --git a/packages/devextreme/js/__internal/grids/grid_core/ai_chat/types.ts b/packages/devextreme/js/__internal/grids/grid_core/ai_chat/types.ts new file mode 100644 index 000000000000..ec50b55fb31a --- /dev/null +++ b/packages/devextreme/js/__internal/grids/grid_core/ai_chat/types.ts @@ -0,0 +1,16 @@ +import type { dxElementWrapper } from '@js/core/renderer'; +import type { Properties as ChatProperties } from '@js/ui/chat'; +import type { Properties as PopupProperties } from '@js/ui/popup'; + +import type { CreateComponent } from '../m_types'; + +export interface AIChatOptions { + container: dxElementWrapper; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + createComponent: CreateComponent; + onMessageEntered?: () => void; + onChatCleared?: () => void; + onRegenerate?: () => void; + popupOptions?: PopupProperties; + chatOptions?: ChatProperties; +} diff --git a/packages/devextreme/js/__internal/grids/grid_core/m_types.ts b/packages/devextreme/js/__internal/grids/grid_core/m_types.ts index 605f88240eaa..b2311a123c62 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/m_types.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/m_types.ts @@ -205,6 +205,7 @@ export interface Controllers { toastViewController: import('./toast/m_toast_controller').ToastViewController; aiColumn: import('./ai_column/controllers/m_ai_column_controller').AIColumnController; aiPromptEditor: import('./ai_column/controllers/m_ai_prompt_editor_view_controller').AIPromptEditorViewController; + aiAssistant: import('./ai_assistant/m_ai_assistant_view_controller').AIAssistantViewController; } type ControllerTypes = { @@ -229,6 +230,7 @@ export interface Views { filterPanelView: import('./filter/m_filter_panel').FilterPanelView; toastView: import('./toast/m_toast_view').ToastView; aiPromptEditorView: import('./ai_column/views/m_ai_prompt_editor_view').AIPromptEditorView; + aiAssistantView: import('./ai_assistant/m_ai_assistant_view').AIAssistantView; } export interface EditingControllerRequired { diff --git a/packages/devextreme/js/__internal/grids/grid_core/views/m_grid_view.ts b/packages/devextreme/js/__internal/grids/grid_core/views/m_grid_view.ts index 3240d317ebbd..1ef32df7ad38 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/views/m_grid_view.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/views/m_grid_view.ts @@ -52,6 +52,7 @@ const VIEW_NAMES = [ 'filterBuilderView', 'toastView', 'aiPromptEditorView', + 'aiAssistantView', ]; const E2E_ATTRIBUTES = { diff --git a/packages/devextreme/js/__internal/grids/tree_list/m_widget.ts b/packages/devextreme/js/__internal/grids/tree_list/m_widget.ts index 574c60903f3c..81fbd8d7b797 100644 --- a/packages/devextreme/js/__internal/grids/tree_list/m_widget.ts +++ b/packages/devextreme/js/__internal/grids/tree_list/m_widget.ts @@ -30,5 +30,6 @@ import './module_not_extended/virtual_columns'; import './m_focus'; import './module_not_extended/row_dragging'; import './module_not_extended/toast'; +import './module_not_extended/ai_assistant'; export default TreeList; diff --git a/packages/devextreme/js/__internal/grids/tree_list/m_widget_base.ts b/packages/devextreme/js/__internal/grids/tree_list/m_widget_base.ts index c9ec6a1a9716..c933bd272e7e 100644 --- a/packages/devextreme/js/__internal/grids/tree_list/m_widget_base.ts +++ b/packages/devextreme/js/__internal/grids/tree_list/m_widget_base.ts @@ -38,6 +38,7 @@ treeListCore.registerModulesOrder([ 'columnHeaders', 'filterRow', 'headerPanel', + 'aiAssistant', 'headerFilter', 'sorting', 'search', diff --git a/packages/devextreme/js/__internal/grids/tree_list/module_not_extended/ai_assistant.ts b/packages/devextreme/js/__internal/grids/tree_list/module_not_extended/ai_assistant.ts new file mode 100644 index 000000000000..d17168f3e673 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/tree_list/module_not_extended/ai_assistant.ts @@ -0,0 +1,13 @@ +import { AIAssistantView } from '@ts/grids/grid_core/ai_assistant/m_ai_assistant_view'; +import { AIAssistantViewController } from '@ts/grids/grid_core/ai_assistant/m_ai_assistant_view_controller'; + +import gridCore from '../m_core'; + +gridCore.registerModule('aiAssistant', { + controllers: { + aiAssistant: AIAssistantViewController, + }, + views: { + aiAssistantView: AIAssistantView, + }, +});