@theia/ai-chat-ui 1.61.0-next.8 → 1.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/ai-chat-ui-contribution.d.ts +5 -1
- package/lib/browser/ai-chat-ui-contribution.d.ts.map +1 -1
- package/lib/browser/ai-chat-ui-contribution.js +102 -4
- package/lib/browser/ai-chat-ui-contribution.js.map +1 -1
- package/lib/browser/ai-chat-ui-frontend-module.d.ts.map +1 -1
- package/lib/browser/ai-chat-ui-frontend-module.js +29 -1
- package/lib/browser/ai-chat-ui-frontend-module.js.map +1 -1
- package/lib/browser/chat-input-agent-suggestions.d.ts +11 -0
- package/lib/browser/chat-input-agent-suggestions.d.ts.map +1 -0
- package/lib/browser/chat-input-agent-suggestions.js +76 -0
- package/lib/browser/chat-input-agent-suggestions.js.map +1 -0
- package/lib/browser/chat-input-widget.d.ts +17 -6
- package/lib/browser/chat-input-widget.d.ts.map +1 -1
- package/lib/browser/chat-input-widget.js +72 -22
- package/lib/browser/chat-input-widget.js.map +1 -1
- package/lib/browser/chat-node-toolbar-action-contribution.d.ts +8 -0
- package/lib/browser/chat-node-toolbar-action-contribution.d.ts.map +1 -1
- package/lib/browser/chat-node-toolbar-action-contribution.js +55 -1
- package/lib/browser/chat-node-toolbar-action-contribution.js.map +1 -1
- package/lib/browser/chat-response-renderer/code-part-renderer.js +1 -1
- package/lib/browser/chat-response-renderer/code-part-renderer.js.map +1 -1
- package/lib/browser/chat-response-renderer/markdown-part-renderer.d.ts +7 -1
- package/lib/browser/chat-response-renderer/markdown-part-renderer.d.ts.map +1 -1
- package/lib/browser/chat-response-renderer/markdown-part-renderer.js +14 -3
- package/lib/browser/chat-response-renderer/markdown-part-renderer.js.map +1 -1
- package/lib/browser/chat-tree-view/chat-view-tree-input-widget.d.ts +33 -0
- package/lib/browser/chat-tree-view/chat-view-tree-input-widget.d.ts.map +1 -0
- package/lib/browser/chat-tree-view/chat-view-tree-input-widget.js +79 -0
- package/lib/browser/chat-tree-view/chat-view-tree-input-widget.js.map +1 -0
- package/lib/browser/chat-tree-view/chat-view-tree-widget.d.ts +20 -4
- package/lib/browser/chat-tree-view/chat-view-tree-widget.d.ts.map +1 -1
- package/lib/browser/chat-tree-view/chat-view-tree-widget.js +180 -34
- package/lib/browser/chat-tree-view/chat-view-tree-widget.js.map +1 -1
- package/lib/browser/chat-view-commands.d.ts +3 -0
- package/lib/browser/chat-view-commands.d.ts.map +1 -1
- package/lib/browser/chat-view-commands.js +15 -0
- package/lib/browser/chat-view-commands.js.map +1 -1
- package/lib/browser/chat-view-contribution.d.ts +1 -0
- package/lib/browser/chat-view-contribution.d.ts.map +1 -1
- package/lib/browser/chat-view-contribution.js +16 -14
- package/lib/browser/chat-view-contribution.js.map +1 -1
- package/lib/browser/chat-view-language-contribution.d.ts +3 -3
- package/lib/browser/chat-view-language-contribution.d.ts.map +1 -1
- package/lib/browser/chat-view-language-contribution.js +9 -22
- package/lib/browser/chat-view-language-contribution.js.map +1 -1
- package/lib/browser/chat-view-widget.d.ts +6 -2
- package/lib/browser/chat-view-widget.d.ts.map +1 -1
- package/lib/browser/chat-view-widget.js +36 -19
- package/lib/browser/chat-view-widget.js.map +1 -1
- package/package.json +12 -12
- package/src/browser/ai-chat-ui-contribution.ts +93 -6
- package/src/browser/ai-chat-ui-frontend-module.ts +31 -3
- package/src/browser/chat-input-agent-suggestions.tsx +85 -0
- package/src/browser/chat-input-widget.tsx +122 -32
- package/src/browser/chat-node-toolbar-action-contribution.ts +40 -1
- package/src/browser/chat-response-renderer/code-part-renderer.tsx +3 -3
- package/src/browser/chat-response-renderer/markdown-part-renderer.tsx +19 -2
- package/src/browser/chat-tree-view/chat-view-tree-input-widget.tsx +89 -0
- package/src/browser/chat-tree-view/chat-view-tree-widget.tsx +199 -16
- package/src/browser/chat-view-commands.ts +18 -0
- package/src/browser/chat-view-contribution.ts +20 -16
- package/src/browser/chat-view-language-contribution.ts +10 -24
- package/src/browser/chat-view-widget.tsx +18 -5
- package/src/browser/style/index.css +58 -4
|
@@ -15,9 +15,13 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
18
|
-
import { CommandRegistry, isOSX, nls, QuickInputButton, QuickInputService, QuickPickItem } from '@theia/core';
|
|
18
|
+
import { CommandRegistry, Emitter, isOSX, MessageService, nls, QuickInputButton, QuickInputService, QuickPickItem } from '@theia/core';
|
|
19
19
|
import { Widget } from '@theia/core/lib/browser';
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
AI_CHAT_NEW_CHAT_WINDOW_COMMAND,
|
|
22
|
+
AI_CHAT_SHOW_CHATS_COMMAND,
|
|
23
|
+
ChatCommands
|
|
24
|
+
} from './chat-view-commands';
|
|
21
25
|
import { ChatAgentLocation, ChatService } from '@theia/ai-chat';
|
|
22
26
|
import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution';
|
|
23
27
|
import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
|
@@ -28,6 +32,10 @@ import { formatDistance } from 'date-fns';
|
|
|
28
32
|
import * as locales from 'date-fns/locale';
|
|
29
33
|
import { AI_SHOW_SETTINGS_COMMAND } from '@theia/ai-core/lib/browser';
|
|
30
34
|
import { OPEN_AI_HISTORY_VIEW } from '@theia/ai-history/lib/browser/ai-history-contribution';
|
|
35
|
+
import { ChatNodeToolbarCommands } from './chat-node-toolbar-action-contribution';
|
|
36
|
+
import { isEditableRequestNode, type EditableRequestNode } from './chat-tree-view';
|
|
37
|
+
import { TASK_CONTEXT_VARIABLE } from '@theia/ai-chat/lib/browser/task-context-variable';
|
|
38
|
+
import { TaskContextService } from '@theia/ai-chat/lib/browser/task-context-service';
|
|
31
39
|
|
|
32
40
|
export const AI_CHAT_TOGGLE_COMMAND_ID = 'aiChat:toggle';
|
|
33
41
|
|
|
@@ -38,6 +46,10 @@ export class AIChatContribution extends AbstractViewContribution<ChatViewWidget>
|
|
|
38
46
|
protected readonly chatService: ChatService;
|
|
39
47
|
@inject(QuickInputService)
|
|
40
48
|
protected readonly quickInputService: QuickInputService;
|
|
49
|
+
@inject(TaskContextService)
|
|
50
|
+
protected readonly taskContextService: TaskContextService;
|
|
51
|
+
@inject(MessageService)
|
|
52
|
+
protected readonly messageService: MessageService;
|
|
41
53
|
|
|
42
54
|
protected static readonly RENAME_CHAT_BUTTON: QuickInputButton = {
|
|
43
55
|
iconClass: 'codicon-edit',
|
|
@@ -83,14 +95,66 @@ export class AIChatContribution extends AbstractViewContribution<ChatViewWidget>
|
|
|
83
95
|
})
|
|
84
96
|
});
|
|
85
97
|
registry.registerCommand(AI_CHAT_NEW_CHAT_WINDOW_COMMAND, {
|
|
86
|
-
execute: () => this.chatService.createSession(ChatAgentLocation.Panel, { focus: true }),
|
|
87
|
-
isEnabled: widget => this.withWidget(widget, () => true),
|
|
98
|
+
execute: () => this.openView().then(() => this.chatService.createSession(ChatAgentLocation.Panel, { focus: true })),
|
|
88
99
|
isVisible: widget => this.withWidget(widget, () => true),
|
|
89
100
|
});
|
|
101
|
+
registry.registerCommand(ChatCommands.AI_CHAT_NEW_WITH_TASK_CONTEXT, {
|
|
102
|
+
execute: async () => {
|
|
103
|
+
const activeSession = this.chatService.getActiveSession();
|
|
104
|
+
const id = await this.summarizeActiveSession();
|
|
105
|
+
if (!id || !activeSession) { return; }
|
|
106
|
+
const newSession = this.chatService.createSession(ChatAgentLocation.Panel, { focus: true }, activeSession.pinnedAgent);
|
|
107
|
+
const summaryVariable = { variable: TASK_CONTEXT_VARIABLE, arg: id };
|
|
108
|
+
newSession.model.context.addVariables(summaryVariable);
|
|
109
|
+
},
|
|
110
|
+
isVisible: () => false
|
|
111
|
+
});
|
|
112
|
+
registry.registerCommand(ChatCommands.AI_CHAT_SUMMARIZE_CURRENT_SESSION, {
|
|
113
|
+
execute: async () => this.summarizeActiveSession(),
|
|
114
|
+
isVisible: widget => {
|
|
115
|
+
if (widget && !this.withWidget(widget)) { return false; }
|
|
116
|
+
const activeSession = this.chatService.getActiveSession();
|
|
117
|
+
return activeSession?.model.location === ChatAgentLocation.Panel
|
|
118
|
+
&& !this.taskContextService.hasSummary(activeSession);
|
|
119
|
+
},
|
|
120
|
+
isEnabled: widget => {
|
|
121
|
+
if (widget && !this.withWidget(widget)) { return false; }
|
|
122
|
+
const activeSession = this.chatService.getActiveSession();
|
|
123
|
+
return activeSession?.model.location === ChatAgentLocation.Panel
|
|
124
|
+
&& !activeSession.model.isEmpty()
|
|
125
|
+
&& !this.taskContextService.hasSummary(activeSession);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
registry.registerCommand(ChatCommands.AI_CHAT_OPEN_SUMMARY_FOR_CURRENT_SESSION, {
|
|
129
|
+
execute: async () => {
|
|
130
|
+
const id = await this.summarizeActiveSession();
|
|
131
|
+
if (!id) { return; }
|
|
132
|
+
await this.taskContextService.open(id);
|
|
133
|
+
},
|
|
134
|
+
isVisible: widget => {
|
|
135
|
+
if (widget && !this.withWidget(widget)) { return false; }
|
|
136
|
+
const activeSession = this.chatService.getActiveSession();
|
|
137
|
+
return !!activeSession && this.taskContextService.hasSummary(activeSession);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
90
140
|
registry.registerCommand(AI_CHAT_SHOW_CHATS_COMMAND, {
|
|
91
141
|
execute: () => this.selectChat(),
|
|
92
|
-
isEnabled: widget => this.withWidget(widget
|
|
93
|
-
isVisible: widget => this.withWidget(widget
|
|
142
|
+
isEnabled: widget => this.withWidget(widget) && this.chatService.getSessions().length > 1,
|
|
143
|
+
isVisible: widget => this.withWidget(widget)
|
|
144
|
+
});
|
|
145
|
+
registry.registerCommand(ChatNodeToolbarCommands.EDIT, {
|
|
146
|
+
isEnabled: node => isEditableRequestNode(node) && !node.request.isEditing,
|
|
147
|
+
isVisible: node => isEditableRequestNode(node) && !node.request.isEditing,
|
|
148
|
+
execute: (node: EditableRequestNode) => {
|
|
149
|
+
node.request.enableEdit();
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
registry.registerCommand(ChatNodeToolbarCommands.CANCEL, {
|
|
153
|
+
isEnabled: node => isEditableRequestNode(node) && node.request.isEditing,
|
|
154
|
+
isVisible: node => isEditableRequestNode(node) && node.request.isEditing,
|
|
155
|
+
execute: (node: EditableRequestNode) => {
|
|
156
|
+
node.request.cancelEdit();
|
|
157
|
+
}
|
|
94
158
|
});
|
|
95
159
|
}
|
|
96
160
|
|
|
@@ -123,6 +187,19 @@ export class AIChatContribution extends AbstractViewContribution<ChatViewWidget>
|
|
|
123
187
|
priority: 1,
|
|
124
188
|
isVisible: widget => this.withWidget(widget),
|
|
125
189
|
});
|
|
190
|
+
const sessionSummarizibilityChangedEmitter = new Emitter<void>();
|
|
191
|
+
this.taskContextService.onDidChange(() => sessionSummarizibilityChangedEmitter.fire());
|
|
192
|
+
this.chatService.onSessionEvent(event => event.type === 'activeChange' && sessionSummarizibilityChangedEmitter.fire());
|
|
193
|
+
registry.registerItem({
|
|
194
|
+
id: 'chat-view.' + ChatCommands.AI_CHAT_SUMMARIZE_CURRENT_SESSION.id,
|
|
195
|
+
command: ChatCommands.AI_CHAT_SUMMARIZE_CURRENT_SESSION.id,
|
|
196
|
+
onDidChange: sessionSummarizibilityChangedEmitter.event
|
|
197
|
+
});
|
|
198
|
+
registry.registerItem({
|
|
199
|
+
id: 'chat-view.' + ChatCommands.AI_CHAT_OPEN_SUMMARY_FOR_CURRENT_SESSION.id,
|
|
200
|
+
command: ChatCommands.AI_CHAT_OPEN_SUMMARY_FOR_CURRENT_SESSION.id,
|
|
201
|
+
onDidChange: sessionSummarizibilityChangedEmitter.event
|
|
202
|
+
});
|
|
126
203
|
}
|
|
127
204
|
|
|
128
205
|
protected async selectChat(sessionId?: string): Promise<void> {
|
|
@@ -211,6 +288,16 @@ export class AIChatContribution extends AbstractViewContribution<ChatViewWidget>
|
|
|
211
288
|
canExtractChatView(chatView: ChatViewWidget): boolean {
|
|
212
289
|
return !chatView.secondaryWindow;
|
|
213
290
|
}
|
|
291
|
+
|
|
292
|
+
protected async summarizeActiveSession(): Promise<string | undefined> {
|
|
293
|
+
const activeSession = this.chatService.getActiveSession();
|
|
294
|
+
if (!activeSession) { return; }
|
|
295
|
+
return this.taskContextService.summarize(activeSession).catch(err => {
|
|
296
|
+
console.warn('Error while summarizing session:', err);
|
|
297
|
+
this.messageService.error('Unable to summarize current session. Please confirm that the summary agent is not disabled.');
|
|
298
|
+
return undefined;
|
|
299
|
+
});
|
|
300
|
+
}
|
|
214
301
|
}
|
|
215
302
|
|
|
216
303
|
function getDateFnsLocale(): locales.Locale {
|
|
@@ -22,7 +22,7 @@ import { ContainerModule, interfaces } from '@theia/core/shared/inversify';
|
|
|
22
22
|
import { EditorSelectionResolver } from '@theia/editor/lib/browser/editor-manager';
|
|
23
23
|
import { AIChatContribution } from './ai-chat-ui-contribution';
|
|
24
24
|
import { AIChatInputConfiguration, AIChatInputWidget } from './chat-input-widget';
|
|
25
|
-
import { ChatNodeToolbarActionContribution } from './chat-node-toolbar-action-contribution';
|
|
25
|
+
import { ChatNodeToolbarActionContribution, DefaultChatNodeToolbarActionContribution } from './chat-node-toolbar-action-contribution';
|
|
26
26
|
import { ChatResponsePartRenderer } from './chat-response-part-renderer';
|
|
27
27
|
import {
|
|
28
28
|
CodePartRenderer,
|
|
@@ -52,6 +52,7 @@ import { ChatViewWidgetToolbarContribution } from './chat-view-widget-toolbar-co
|
|
|
52
52
|
import { ContextVariablePicker } from './context-variable-picker';
|
|
53
53
|
import { ChangeSetActionRenderer, ChangeSetActionService } from './change-set-actions/change-set-action-service';
|
|
54
54
|
import { ChangeSetAcceptAction } from './change-set-actions/change-set-accept-action';
|
|
55
|
+
import { AIChatTreeInputArgs, AIChatTreeInputConfiguration, AIChatTreeInputFactory, AIChatTreeInputWidget } from './chat-tree-view/chat-view-tree-input-widget';
|
|
55
56
|
|
|
56
57
|
export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
|
|
57
58
|
bindViewContribution(bind, AIChatContribution);
|
|
@@ -64,8 +65,9 @@ export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
|
|
|
64
65
|
bind(AIChatInputWidget).toSelf();
|
|
65
66
|
bind(AIChatInputConfiguration).toConstantValue({
|
|
66
67
|
showContext: true,
|
|
67
|
-
showPinnedAgent: true
|
|
68
|
-
|
|
68
|
+
showPinnedAgent: true,
|
|
69
|
+
showChangeSet: true
|
|
70
|
+
} satisfies AIChatInputConfiguration);
|
|
69
71
|
bind(WidgetFactory).toDynamicValue(({ container }) => ({
|
|
70
72
|
id: AIChatInputWidget.ID,
|
|
71
73
|
createWidget: () => container.get(AIChatInputWidget)
|
|
@@ -79,6 +81,30 @@ export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
|
|
|
79
81
|
createWidget: () => container.get(ChatViewTreeWidget)
|
|
80
82
|
})).inSingletonScope();
|
|
81
83
|
|
|
84
|
+
bind(AIChatTreeInputFactory).toFactory(ctx => (args: AIChatTreeInputArgs) => {
|
|
85
|
+
const container = ctx.container.createChild();
|
|
86
|
+
container.bind(AIChatTreeInputArgs).toConstantValue(args);
|
|
87
|
+
container.bind(AIChatTreeInputConfiguration).toConstantValue({
|
|
88
|
+
showContext: true,
|
|
89
|
+
showPinnedAgent: true,
|
|
90
|
+
showChangeSet: false
|
|
91
|
+
} satisfies AIChatInputConfiguration);
|
|
92
|
+
container.bind(AIChatTreeInputWidget).toSelf().inSingletonScope();
|
|
93
|
+
const widget = container.get(AIChatTreeInputWidget);
|
|
94
|
+
const noOp = () => { };
|
|
95
|
+
widget.node.classList.add('chat-input-widget');
|
|
96
|
+
widget.chatModel = args.node.request.session;
|
|
97
|
+
widget.initialValue = args.initialValue;
|
|
98
|
+
widget.setEnabled(true);
|
|
99
|
+
widget.onQuery = args.onQuery;
|
|
100
|
+
// We need to set those values here, otherwise the widget will throw an error
|
|
101
|
+
widget.onUnpin = args.onUnpin ?? noOp;
|
|
102
|
+
widget.onCancel = args.onCancel ?? noOp;
|
|
103
|
+
widget.onDeleteChangeSet = args.onDeleteChangeSet ?? noOp;
|
|
104
|
+
widget.onDeleteChangeSetElement = args.onDeleteChangeSetElement ?? noOp;
|
|
105
|
+
return widget;
|
|
106
|
+
});
|
|
107
|
+
|
|
82
108
|
bind(ContextVariablePicker).toSelf().inSingletonScope();
|
|
83
109
|
|
|
84
110
|
bind(ChatResponsePartRenderer).to(HorizontalLayoutPartRenderer).inSingletonScope();
|
|
@@ -115,6 +141,8 @@ export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
|
|
|
115
141
|
bind(ChangeSetActionRenderer).toService(ChangeSetAcceptAction);
|
|
116
142
|
|
|
117
143
|
bindContributionProvider(bind, ChatNodeToolbarActionContribution);
|
|
144
|
+
bind(DefaultChatNodeToolbarActionContribution).toSelf().inSingletonScope();
|
|
145
|
+
bind(ChatNodeToolbarActionContribution).toService(DefaultChatNodeToolbarActionContribution);
|
|
118
146
|
});
|
|
119
147
|
|
|
120
148
|
function bindChatViewWidget(bind: interfaces.Bind): void {
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2025 EclipseSource GmbH and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import * as React from '@theia/core/shared/react';
|
|
18
|
+
import { DeclaredEventsEventListenerObject, useMarkdownRendering } from './chat-response-renderer/markdown-part-renderer';
|
|
19
|
+
import { OpenerService } from '@theia/core/lib/browser';
|
|
20
|
+
import { ChatSuggestion, ChatSuggestionCallback } from '@theia/ai-chat';
|
|
21
|
+
import { MarkdownString } from '@theia/core/lib/common/markdown-rendering';
|
|
22
|
+
|
|
23
|
+
interface ChatInputAgentSuggestionsProps {
|
|
24
|
+
suggestions: readonly ChatSuggestion[];
|
|
25
|
+
opener: OpenerService;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getText(suggestion: ChatSuggestion): string {
|
|
29
|
+
if (typeof suggestion === 'string') { return suggestion; }
|
|
30
|
+
if ('value' in suggestion) { return suggestion.value; }
|
|
31
|
+
if (typeof suggestion.content === 'string') { return suggestion.content; }
|
|
32
|
+
return suggestion.content.value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getContent(suggestion: ChatSuggestion): string | MarkdownString {
|
|
36
|
+
if (typeof suggestion === 'string') { return suggestion; }
|
|
37
|
+
if ('value' in suggestion) { return suggestion; }
|
|
38
|
+
return suggestion.content;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const ChatInputAgentSuggestions: React.FC<ChatInputAgentSuggestionsProps> = ({ suggestions, opener }) => (
|
|
42
|
+
!!suggestions?.length && <div className="chat-agent-suggestions">
|
|
43
|
+
{suggestions.map(suggestion => <ChatInputAgentSuggestion
|
|
44
|
+
key={getText(suggestion)}
|
|
45
|
+
suggestion={suggestion}
|
|
46
|
+
opener={opener}
|
|
47
|
+
handler={ChatSuggestionCallback.is(suggestion) ? new ChatSuggestionClickHandler(suggestion) : undefined}
|
|
48
|
+
/>)}
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
interface ChatInputAgestSuggestionProps {
|
|
53
|
+
suggestion: ChatSuggestion;
|
|
54
|
+
opener: OpenerService;
|
|
55
|
+
handler?: DeclaredEventsEventListenerObject;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const ChatInputAgentSuggestion: React.FC<ChatInputAgestSuggestionProps> = ({ suggestion, opener, handler }) => {
|
|
59
|
+
const ref = useMarkdownRendering(getContent(suggestion), opener, true, handler);
|
|
60
|
+
return <div className="chat-agent-suggestion" style={(!handler || ChatSuggestionCallback.containsCallbackLink(suggestion)) ? undefined : { cursor: 'pointer' }} ref={ref} />;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
class ChatSuggestionClickHandler implements DeclaredEventsEventListenerObject {
|
|
64
|
+
constructor(protected readonly suggestion: ChatSuggestionCallback) { }
|
|
65
|
+
handleEvent(event: Event): boolean {
|
|
66
|
+
const { target, currentTarget } = event;
|
|
67
|
+
if (event.type !== 'click' || !(target instanceof Element)) { return false; }
|
|
68
|
+
const link = target.closest('a[href^="_callback"]');
|
|
69
|
+
if (link) {
|
|
70
|
+
this.suggestion.callback();
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
if (!(currentTarget instanceof Element)) {
|
|
74
|
+
this.suggestion.callback();
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
const containedLink = currentTarget.querySelector('a[href^="_callback"]');
|
|
78
|
+
// Whole body should count.
|
|
79
|
+
if (!containedLink) {
|
|
80
|
+
this.suggestion.callback();
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|