diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-empty-state (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-empty-state (fluent.blue.light).png index 9f5f9eb027d8..1d6799ab22c4 100644 Binary files a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-empty-state (fluent.blue.light).png and b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-empty-state (fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-error-state (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-error-state (fluent.blue.light).png index 7486964b86e4..598e27033036 100644 Binary files a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-error-state (fluent.blue.light).png and b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-error-state (fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-failure-with-aborted-command (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-failure-with-aborted-command (fluent.blue.light).png index df40743e5353..c7721634953e 100644 Binary files a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-failure-with-aborted-command (fluent.blue.light).png and b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-failure-with-aborted-command (fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-failure-with-error-command (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-failure-with-error-command (fluent.blue.light).png index b44d7cc5075a..e553baa1144b 100644 Binary files a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-failure-with-error-command (fluent.blue.light).png and b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-failure-with-error-command (fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-multiple-messages (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-multiple-messages (fluent.blue.light).png index ca334a81d44b..2a6d76725404 100644 Binary files a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-multiple-messages (fluent.blue.light).png and b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-multiple-messages (fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-pending-state (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-pending-state (fluent.blue.light).png index 7b0597efab64..af26d8c578e3 100644 Binary files a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-pending-state (fluent.blue.light).png and b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-pending-state (fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-pending-state (fluent.blue.light)_mask.png b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-pending-state (fluent.blue.light)_mask.png index 518e8bcd2d6c..a897ed209810 100644 Binary files a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-pending-state (fluent.blue.light)_mask.png and b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-pending-state (fluent.blue.light)_mask.png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-success-multiple-commands (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-success-multiple-commands (fluent.blue.light).png index 910053ca3c9c..f922465a8387 100644 Binary files a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-success-multiple-commands (fluent.blue.light).png and b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-success-multiple-commands (fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-success-state (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-success-state (fluent.blue.light).png index df9553fefb96..a9f5ab8adae5 100644 Binary files a/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-success-state (fluent.blue.light).png and b/e2e/testcafe-devextreme/tests/dataGrid/common/aiAssistant/etalons/datagrid-ai-assistant-success-state (fluent.blue.light).png differ diff --git a/packages/devextreme/js/__internal/grids/grid_core/__tests__/__mock__/model/ai_chat.ts b/packages/devextreme/js/__internal/grids/grid_core/__tests__/__mock__/model/ai_chat.ts index 149dbe872c27..df3ebb3483da 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/__tests__/__mock__/model/ai_chat.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/__tests__/__mock__/model/ai_chat.ts @@ -2,6 +2,7 @@ import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import { MessageStatus } from '@ts/grids/grid_core/ai_assistant/const'; import { CLASSES } from '@ts/grids/grid_core/ai_chat/const'; +import { OVERLAY_CONTENT_CLASS } from '@ts/ui/overlay/overlay'; export class AIChatModel { protected readonly root: dxElementWrapper; @@ -51,4 +52,12 @@ export class AIChatModel { public getRegenerateButtonTitle(messageIndex: number): string { return this.getRegenerateButton(messageIndex)?.getAttribute('title') ?? ''; } + + public getPopupContentElement(): dxElementWrapper { + return this.root.find(`.${OVERLAY_CONTENT_CLASS}`); + } + + public getPopupHeight(): string { + return (this.getPopupContentElement().get(0) as HTMLElement)?.style.height ?? ''; + } } diff --git a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/__tests__/ai_assistant_view.integration.test.ts b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/__tests__/ai_assistant_view.integration.test.ts new file mode 100644 index 000000000000..17fad6383c98 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/__tests__/ai_assistant_view.integration.test.ts @@ -0,0 +1,63 @@ +import { + afterEach, + beforeEach, + describe, + expect, + it, + jest, +} from '@jest/globals'; +import type { Properties as DataGridProperties } from '@js/ui/data_grid'; +import { + afterTest, + beforeTest, + createDataGrid, +} from '@ts/grids/grid_core/__tests__/__mock__/helpers/utils'; +import { AIAssistantDataGridModel } from '@ts/grids/grid_core/__tests__/__mock__/model/ai_assistant'; + +const LOCAL_DATA = [ + { id: 1, name: 'Alpha' }, + { id: 2, name: 'Beta' }, +]; + +const DEFAULT_COLUMNS = [ + { dataField: 'id', caption: 'ID', dataType: 'number' as const }, + { dataField: 'name', caption: 'Name', dataType: 'string' as const }, +]; + +const createDataGridWithAIAndPopup = async ( + aiAssistantOptions: DataGridProperties['aiAssistant'] = {}, +): Promise => { + await createDataGrid({ + dataSource: LOCAL_DATA, + columns: DEFAULT_COLUMNS, + aiAssistant: { enabled: true, title: 'AI Assistant', ...aiAssistantOptions }, + }); + + const model = new AIAssistantDataGridModel( + document.getElementById('gridContainer') as HTMLElement, + ); + + await model.togglePopup(); + jest.runAllTimers(); + + return model; +}; + +describe('AIAssistantView', () => { + beforeEach(beforeTest); + afterEach(afterTest); + + describe('popup height', () => { + it('should render popup with 560px height by default', async () => { + const model = await createDataGridWithAIAndPopup(); + + expect(model.getAiChatModel().getPopupHeight()).toBe('560px'); + }); + + it('should render popup with custom height set via aiAssistant.popup.height option', async () => { + const model = await createDataGridWithAIAndPopup({ popup: { height: 600 } }); + + expect(model.getAiChatModel().getPopupHeight()).toBe('600px'); + }); + }); +}); diff --git a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_view.ts b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_view.ts index 2cdec61b0e02..e7a41bbbfb84 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_view.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_view.ts @@ -1,13 +1,11 @@ import type { PositionConfig } from '@js/common/core/animation'; import type { ArrayStore } from '@js/common/data'; import type { Callback } from '@js/core/utils/callbacks'; -import { getHeight } from '@js/core/utils/size'; import type { Message, Properties as ChatProperties } from '@js/ui/chat'; import type { HidingEvent, Properties as PopupProperties } from '@js/ui/popup'; import { fromPromise } from '@ts/core/utils/m_deferred'; import type { ColumnHeadersView } from '@ts/grids/grid_core/column_headers/m_column_headers'; import type { OptionChanged } from '@ts/grids/grid_core/m_types'; -import type { RowsView } from '@ts/grids/grid_core/views/m_rows_view'; import type { DataChange } from '@ts/ui/collection/collection_widget.base'; import { AIChat } from '../ai_chat/ai_chat'; @@ -34,8 +32,6 @@ export class AIAssistantView extends View { private columnHeadersView!: ColumnHeadersView; - private rowsView!: RowsView; - private handleMessageStorePushContext!: (changes: DataChange[]) => void; private isHidingAfterConfirm = false; @@ -44,7 +40,6 @@ export class AIAssistantView extends View { public init(): void { this.columnHeadersView = this.getView('columnHeadersView'); - this.rowsView = this.getView('rowsView'); this.aiAssistantController = this.getController('aiAssistant'); this.messageStore = this.aiAssistantController.getMessageStore(); this.handleMessageStorePushContext = this.handleMessageStorePush.bind(this); @@ -68,13 +63,6 @@ export class AIAssistantView extends View { }; } - private getPopupHeight(): number { - const headersHeight = this.columnHeadersView.getHeight(); - const rowsViewHeight = getHeight(this.rowsView.element()); - - return headersHeight + rowsViewHeight - AI_ASSISTANT_POPUP_OFFSET * 2; - } - private getAIChatPopupOptions(): PopupProperties { const position: PositionConfig = { my: 'right top', @@ -85,15 +73,9 @@ export class AIAssistantView extends View { boundaryOffset: `${AI_ASSISTANT_POPUP_OFFSET} ${AI_ASSISTANT_POPUP_OFFSET}`, }; - // @ts-ignore return { title: this.option('aiAssistant.title') ?? '', position, - // NOTE: DevExtreme Popup supports function-valued height at runtime - // (re-evaluated automatically on show and window resize). - // @ts-expect-error type declaration - height: () => this.getPopupHeight(), - _ignoreFunctionValueDeprecation: true, onShowing: (): void => { this.visibilityChanged?.fire(true); }, 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 6fb04fbbf2df..2506238772ea 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 @@ -4,6 +4,7 @@ import { TEXTAREA_CLASS } from '@ts/ui/text_area'; export const DEFAULT_POPUP_OPTIONS = { width: 400, minWidth: 400, + height: 560, minHeight: 480, visible: false, shading: false,