DataGrid - AI Assistant: Implement messageTemplate#33265
DataGrid - AI Assistant: Implement messageTemplate#33265Alyar666 wants to merge 11 commits intoDevExpress:26_1from
Conversation
There was a problem hiding this comment.
Pull request overview
Implements richer AI Assistant chat message rendering in the DataGrid/TreeList AI Assistant UI, introducing status-aware message templates (pending/success/error) and moving message state management into a dedicated controller.
Changes:
- Add
messageTemplaterendering for AI Assistant messages (status icon/header/body, command result list, pending progress bar, regenerate action). - Introduce
AIAssistantControllerto manage message store/data source and AI request lifecycle. - Refactor/extend AI chat styles (new
aiChatlayout, theme-specific includes) and add new localization keys for message headers.
Reviewed changes
Copilot reviewed 57 out of 57 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/devextreme/js/localization/messages/ar.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/bg.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/ca.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/cs.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/da.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/de.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/el.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/en.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/es.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/fa.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/fi.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/fr.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/hu.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/it.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/ja.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/ko.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/lt.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/lv.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/nb.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/nl.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/pl.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/pt.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/ro.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/ru.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/sl.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/sv.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/tr.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/uk.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/vi.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/zh.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/localization/messages/zh-tw.json | Add AI chat pending/error header message keys |
| packages/devextreme/js/__internal/grids/tree_list/module_not_extended/ai_assistant.ts | Register new AI assistant controller and keep view controller under a new key |
| packages/devextreme/js/__internal/grids/data_grid/module_not_extended/ai_assistant.ts | Register new AI assistant controller and keep view controller under a new key |
| packages/devextreme/js/__internal/grids/grid_core/m_types.ts | Update controller type map for new AI assistant controller naming |
| packages/devextreme/js/__internal/grids/grid_core/ai_chat/types.ts | Re-export command result types and add message status union type |
| packages/devextreme/js/__internal/grids/grid_core/ai_chat/const.ts | Expand AI chat CSS class constants and add regenerate/icon constants |
| packages/devextreme/js/__internal/grids/grid_core/ai_chat/ai_chat.ts | Implement custom messageTemplate rendering and status-specific UI |
| packages/devextreme/js/__internal/grids/grid_core/ai_chat/ai_chat.test.ts | Add Jest coverage for new message template behaviors |
| packages/devextreme/js/__internal/grids/grid_core/ai_assistant/types.ts | Introduce AI command/response/result types and callbacks contract |
| packages/devextreme/js/__internal/grids/grid_core/ai_assistant/grid_commands.ts | Add placeholder grid command validation/execution layer |
| packages/devextreme/js/__internal/grids/grid_core/ai_assistant/const.ts | Add AI assistant author constants and shared message status enum |
| packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_view.ts | Move message data source + request sending into controller |
| packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_controller.ts | New controller: message store lifecycle, AI integration callbacks, status transitions |
| packages/devextreme/js/__internal/grids/grid_core/ai_assistant/tests/ai_assistant_view.test.ts | Update tests to mock controller-driven data source and message sending |
| packages/devextreme/js/__internal/grids/grid_core/ai_assistant/tests/ai_assistant_controller.test.ts | Add unit tests for controller request lifecycle and message updates |
| packages/devextreme-scss/scss/widgets/material/gridBase/layout/aiChat/_index.scss | Theme include for new aiChat mixins |
| packages/devextreme-scss/scss/widgets/material/gridBase/_index.scss | Wire aiChat layout module and remove inline empty-view include |
| packages/devextreme-scss/scss/widgets/generic/gridBase/layout/aiChat/_index.scss | Theme include for new aiChat mixins |
| packages/devextreme-scss/scss/widgets/generic/gridBase/_index.scss | Wire aiChat layout module and remove inline empty-view include |
| packages/devextreme-scss/scss/widgets/fluent/gridBase/layout/aiChat/_index.scss | Theme include for new aiChat mixins |
| packages/devextreme-scss/scss/widgets/fluent/gridBase/_index.scss | Wire aiChat layout module and remove inline empty-view include |
| packages/devextreme-scss/scss/widgets/base/gridBase/layout/aiChat/_mixins.scss | New mixins for empty view and pending message styling |
| packages/devextreme-scss/scss/widgets/base/gridBase/layout/aiChat/_index.scss | New base aiChat layout styles (message template layout + progress bar positioning) |
| packages/devextreme-scss/scss/widgets/base/gridBase/layout/ai-chat/_mixins.scss | Remove legacy ai-chat mixins (superseded by aiChat) |
| packages/devextreme-scss/scss/widgets/base/gridBase/layout/ai-chat/_index.scss | Remove legacy ai-chat base styles (superseded by aiChat) |
| packages/devextreme-scss/scss/widgets/base/gridBase/_mixins.scss | Remove legacy forward for ai-chat mixins (path removed) |
| packages/devextreme-scss/scss/widgets/base/gridBase/_index.scss | Switch base gridBase to use new layout/aiChat module |
| data: { | ||
| id: aiMessageId, | ||
| timestamp: parsedTimestamp, | ||
| // TODO: need to localize author name and move it to constants or options |
There was a problem hiding this comment.
This TODO is partially outdated: the author is already centralized in AI_ASSISTANT_AUTHOR constants. Consider updating the comment to focus on the remaining work (e.g., localization/configurability), so it doesn’t imply the constant extraction is still pending.
| // TODO: need to localize author name and move it to constants or options | |
| // TODO: need to make author name configurable/localizable |
| @@ -0,0 +1,85 @@ | |||
| @use "../../../icon_fonts" as *; | |||
There was a problem hiding this comment.
I'd suggest to have screen shot etalons in different themes, so the designer could review them.
And the story book.
| .addClass(`dx-icon dx-icon-${REGENERATE_ICON} ${CLASSES.messageRegenerateButton}`) | ||
| .appendTo($row); | ||
|
|
||
| eventsEngine.on($button, 'click', () => this.options.onRegenerate?.()); |
There was a problem hiding this comment.
would event be automatically unsubscribed when button is removed from DOM after succesful regeneration or when the result can no longer be regenerated? Purhaps. we should use eventsEngine.one instead - as long as we re-render messageBubble after each change
There was a problem hiding this comment.
When an element is removed from the DOM, all associated subscriptions are also cleaned up (assuming there are no remaining references to that element).
Using eventsEngine.one is unlikely to fully resolve the issue you described.
8c67a26 to
0ffb5d5
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 59 out of 59 changed files in this pull request and generated 7 comments.
Comments suppressed due to low confidence (1)
packages/devextreme/js/__internal/grids/grid_core/ai_chat/types.ts:21
MessageStatusis declared here as a string union but isn’t used (the implementation usesMessageStatusfromai_assistant/const). This extra exported type is redundant and may cause confusion about which status type to use; consider removing it or aligning the code to use a single source of truth.
export type MessageStatus = 'pending' | 'success' | 'error';
| public sendRequestToAI(message: Message): void { | ||
| const aiMessageId = this.createPendingAIMessage(message); | ||
|
|
||
| this.aiAssistantIntegrationController?.sendRequest(message.text, { | ||
| onComplete: (response: ExecuteGridAssistantCommandResult): void => { | ||
| fromPromise(this.processResponse(response)) | ||
| .done((commands: CommandResults) => { | ||
| this.completeAIMessage(aiMessageId, commands); | ||
| }) | ||
| .fail((errorMessage) => { | ||
| const error = errorMessage instanceof Error | ||
| ? errorMessage | ||
| : new Error(String(errorMessage)); | ||
|
|
||
| this.failAIMessage(aiMessageId, error); | ||
| }); | ||
| }, | ||
| onError: (error: Error): void => { | ||
| this.failAIMessage(aiMessageId, error); | ||
| }, | ||
| }); | ||
| } |
There was a problem hiding this comment.
sendRequestToAI always inserts a pending assistant message before calling sendRequest. If AI integration is not configured, AIAssistantIntegrationController.sendRequest returns early (and abort prevents callbacks), so the message will remain in the pending state indefinitely. Consider detecting this case (e.g., make sendRequest return a boolean / throw when no integration) and immediately mark the message as Error (or avoid inserting it) with a user-friendly error.
| public sendRequestToAI(message: Message): void { | ||
| const aiMessageId = this.createPendingAIMessage(message); | ||
|
|
||
| this.aiAssistantIntegrationController?.sendRequest(message.text, { | ||
| onComplete: (response: ExecuteGridAssistantCommandResult): void => { | ||
| fromPromise(this.processResponse(response)) | ||
| .done((commands: CommandResults) => { | ||
| this.completeAIMessage(aiMessageId, commands); | ||
| }) | ||
| .fail((errorMessage) => { | ||
| const error = errorMessage instanceof Error | ||
| ? errorMessage | ||
| : new Error(String(errorMessage)); | ||
|
|
||
| this.failAIMessage(aiMessageId, error); | ||
| }); | ||
| }, | ||
| onError: (error: Error): void => { | ||
| this.failAIMessage(aiMessageId, error); | ||
| }, | ||
| }); | ||
| } |
There was a problem hiding this comment.
A new request aborts the previous one in AIAssistantIntegrationController.sendRequest(), and RequestManager suppresses callbacks after abort. Since the controller doesn’t track/resolve the previously inserted pending message, sending multiple prompts can leave older assistant messages stuck in Pending forever. Consider keeping the previous pending message id and marking it as canceled/failed (or removing it) when a request is aborted/replaced.
|
|
||
| "dxDataGrid-aiAssistantTitle": "AI Assistant", | ||
| "dxDataGrid-aiAssistantPendingMessageHeader": "Request in progress", | ||
| "dxDataGrid-aiAssistantProcessingMessage": "Processing...", |
There was a problem hiding this comment.
message list differ for other languages
No description provided.