@gitlab/ui 104.2.0 → 105.0.1

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.
Files changed (84) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/index.css +1 -1
  3. package/dist/index.css.map +1 -1
  4. package/dist/index.js +0 -5
  5. package/dist/tailwind.css +1 -1
  6. package/dist/tailwind.css.map +1 -1
  7. package/dist/vendor/bootstrap-vue/src/mixins/form-radio-check.js +0 -4
  8. package/package.json +1 -3
  9. package/src/index.js +0 -5
  10. package/src/scss/components.scss +0 -3
  11. package/src/vendor/bootstrap-vue/src/mixins/form-radio-check.js +0 -1
  12. package/translations.js +0 -57
  13. package/dist/components/experimental/duo/chat/components/duo_chat_context/constants.js +0 -21
  14. package/dist/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_details_modal/duo_chat_context_item_details_modal.js +0 -159
  15. package/dist/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu.js +0 -273
  16. package/dist/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu_category_items.js +0 -77
  17. package/dist/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu_search_item.js +0 -89
  18. package/dist/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu_search_items.js +0 -147
  19. package/dist/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu_search_items_loading.js +0 -61
  20. package/dist/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_popover/duo_chat_context_item_popover.js +0 -137
  21. package/dist/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_selections/duo_chat_context_item_selections.js +0 -163
  22. package/dist/components/experimental/duo/chat/components/duo_chat_context/mock_context_data.js +0 -308
  23. package/dist/components/experimental/duo/chat/components/duo_chat_context/utils.js +0 -140
  24. package/dist/components/experimental/duo/chat/components/duo_chat_conversation/duo_chat_conversation.js +0 -109
  25. package/dist/components/experimental/duo/chat/components/duo_chat_loader/duo_chat_loader.js +0 -111
  26. package/dist/components/experimental/duo/chat/components/duo_chat_message/buttons_utils.js +0 -33
  27. package/dist/components/experimental/duo/chat/components/duo_chat_message/constants.js +0 -14
  28. package/dist/components/experimental/duo/chat/components/duo_chat_message/copy_code_element.js +0 -24
  29. package/dist/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.js +0 -300
  30. package/dist/components/experimental/duo/chat/components/duo_chat_message/insert_code_snippet_element.js +0 -56
  31. package/dist/components/experimental/duo/chat/components/duo_chat_message/utils.js +0 -17
  32. package/dist/components/experimental/duo/chat/components/duo_chat_message_sources/duo_chat_message_sources.js +0 -115
  33. package/dist/components/experimental/duo/chat/components/duo_chat_predefined_prompts/duo_chat_predefined_prompts.js +0 -72
  34. package/dist/components/experimental/duo/chat/constants.js +0 -35
  35. package/dist/components/experimental/duo/chat/duo_chat.js +0 -553
  36. package/dist/components/experimental/duo/chat/markdown_renderer.js +0 -25
  37. package/dist/components/experimental/duo/chat/mock_data.js +0 -170
  38. package/dist/components/experimental/duo/user_feedback/user_feedback.js +0 -106
  39. package/dist/components/experimental/duo/user_feedback/user_feedback_modal.js +0 -154
  40. package/dist/components/experimental/duo/workflow/components/duo_workflow_panel/duo_workflow_panel.js +0 -106
  41. package/dist/components/experimental/duo/workflow/components/duo_workflow_prompt/duo_workflow_prompt.js +0 -246
  42. package/src/components/experimental/duo/chat/components/duo_chat_context/constants.js +0 -21
  43. package/src/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_details_modal/duo_chat_context_item_details_modal.vue +0 -182
  44. package/src/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu.md +0 -44
  45. package/src/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu.vue +0 -288
  46. package/src/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu_category_items.vue +0 -54
  47. package/src/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu_search_item.vue +0 -86
  48. package/src/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu_search_items.vue +0 -168
  49. package/src/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu_search_items_loading.vue +0 -43
  50. package/src/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_popover/duo_chat_context_item_popover.vue +0 -170
  51. package/src/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_selections/duo_chat_context_item_selections.vue +0 -196
  52. package/src/components/experimental/duo/chat/components/duo_chat_context/mock_context_data.js +0 -362
  53. package/src/components/experimental/duo/chat/components/duo_chat_context/utils.js +0 -169
  54. package/src/components/experimental/duo/chat/components/duo_chat_conversation/duo_chat_conversation.md +0 -27
  55. package/src/components/experimental/duo/chat/components/duo_chat_conversation/duo_chat_conversation.vue +0 -99
  56. package/src/components/experimental/duo/chat/components/duo_chat_loader/duo_chat_loader.md +0 -10
  57. package/src/components/experimental/duo/chat/components/duo_chat_loader/duo_chat_loader.scss +0 -44
  58. package/src/components/experimental/duo/chat/components/duo_chat_loader/duo_chat_loader.vue +0 -112
  59. package/src/components/experimental/duo/chat/components/duo_chat_message/buttons_utils.js +0 -39
  60. package/src/components/experimental/duo/chat/components/duo_chat_message/constants.js +0 -12
  61. package/src/components/experimental/duo/chat/components/duo_chat_message/copy_code_element.js +0 -24
  62. package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.md +0 -69
  63. package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.scss +0 -105
  64. package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.vue +0 -363
  65. package/src/components/experimental/duo/chat/components/duo_chat_message/insert_code_snippet_element.js +0 -51
  66. package/src/components/experimental/duo/chat/components/duo_chat_message/utils.js +0 -18
  67. package/src/components/experimental/duo/chat/components/duo_chat_message_sources/duo_chat_message_sources.md +0 -10
  68. package/src/components/experimental/duo/chat/components/duo_chat_message_sources/duo_chat_message_sources.vue +0 -91
  69. package/src/components/experimental/duo/chat/components/duo_chat_predefined_prompts/duo_chat_predefined_prompts.md +0 -10
  70. package/src/components/experimental/duo/chat/components/duo_chat_predefined_prompts/duo_chat_predefined_prompts.vue +0 -45
  71. package/src/components/experimental/duo/chat/constants.js +0 -37
  72. package/src/components/experimental/duo/chat/duo_chat.md +0 -202
  73. package/src/components/experimental/duo/chat/duo_chat.scss +0 -413
  74. package/src/components/experimental/duo/chat/duo_chat.vue +0 -751
  75. package/src/components/experimental/duo/chat/markdown_renderer.js +0 -29
  76. package/src/components/experimental/duo/chat/mock_data.js +0 -187
  77. package/src/components/experimental/duo/chat/variables.scss +0 -9
  78. package/src/components/experimental/duo/user_feedback/user_feedback.md +0 -90
  79. package/src/components/experimental/duo/user_feedback/user_feedback.vue +0 -95
  80. package/src/components/experimental/duo/user_feedback/user_feedback_modal.vue +0 -167
  81. package/src/components/experimental/duo/workflow/components/duo_workflow_panel/duo_workflow_panel.md +0 -42
  82. package/src/components/experimental/duo/workflow/components/duo_workflow_panel/duo_workflow_panel.vue +0 -96
  83. package/src/components/experimental/duo/workflow/components/duo_workflow_prompt/duo_workflow_prompt.md +0 -46
  84. package/src/components/experimental/duo/workflow/components/duo_workflow_prompt/duo_workflow_prompt.vue +0 -270
@@ -1,553 +0,0 @@
1
- import throttle from 'lodash/throttle';
2
- import emptySvg from '@gitlab/svgs/dist/illustrations/empty-state/empty-activity-md.svg';
3
- import GlDropdownItem from '../../../base/dropdown/dropdown_item';
4
- import GlCard from '../../../base/card/card';
5
- import GlEmptyState from '../../../regions/empty_state/empty_state';
6
- import GlButton from '../../../base/button/button';
7
- import GlAlert from '../../../base/alert/alert';
8
- import GlFormInputGroup from '../../../base/form/form_input_group/form_input_group';
9
- import GlFormTextarea from '../../../base/form/form_textarea/form_textarea';
10
- import GlForm from '../../../base/form/form';
11
- import GlExperimentBadge from '../../experiment_badge/experiment_badge';
12
- import { badgeTypes, badgeTypeValidator } from '../../experiment_badge/constants';
13
- import { SafeHtmlDirective } from '../../../../directives/safe_html/safe_html';
14
- import { translate } from '../../../../utils/i18n';
15
- import GlDuoChatLoader from './components/duo_chat_loader/duo_chat_loader';
16
- import GlDuoChatPredefinedPrompts from './components/duo_chat_predefined_prompts/duo_chat_predefined_prompts';
17
- import GlDuoChatConversation from './components/duo_chat_conversation/duo_chat_conversation';
18
- import { CHAT_RESET_MESSAGE, CHAT_INCLUDE_MESSAGE, MESSAGE_MODEL_ROLES, CHAT_CLEAR_MESSAGE } from './constants';
19
- import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
20
-
21
- /**
22
- * This component has been migrated to the Duo-UI library (https://gitlab.com/gitlab-org/duo-ui).
23
- *
24
- * Please use the corresponding component in Duo-UI going forward.
25
- * All future development and maintenance for Duo components should take place in Duo-UI.
26
- *
27
- * For more details, see the migration epic: https://gitlab.com/groups/gitlab-org/-/epics/15344 or reach out to the Duo-Chat team in #g_duo_chat.
28
- */
29
- const i18n = {
30
- CHAT_DEFAULT_TITLE: translate('GlDuoChat.chatDefaultTitle', 'GitLab Duo Chat'),
31
- CHAT_CLOSE_LABEL: translate('GlDuoChat.chatCloseLabel', 'Close the Code Explanation'),
32
- CHAT_EMPTY_STATE_TITLE: translate('GlDuoChat.chatEmptyStateTitle', 'Ask a question'),
33
- CHAT_EMPTY_STATE_DESC: translate('GlDuoChat.chatEmptyStateDesc', 'GitLab Duo Chat is your AI-powered assistant.'),
34
- CHAT_EMPTY_STATE_SECONDARY_DESC: translate('GlDuoChat.chatEmptyStateSecondaryDesc', 'Responses may be inaccurate. Verify before use.'),
35
- CHAT_PROMPT_PLACEHOLDER_DEFAULT: translate('GlDuoChat.chatPromptPlaceholderDefault', 'GitLab Duo Chat'),
36
- CHAT_PROMPT_PLACEHOLDER_WITH_COMMANDS: translate('GlDuoChat.chatPromptPlaceholderWithCommands', 'Type /help to learn more'),
37
- CHAT_SUBMIT_LABEL: translate('GlDuoChat.chatSubmitLabel', 'Send chat message.'),
38
- CHAT_CANCEL_LABEL: translate('GlDuoChat.chatCancelLabel', 'Cancel'),
39
- CHAT_DEFAULT_PREDEFINED_PROMPTS: [translate('GlDuoChat.chatDefaultPredefinedPromptsChangePassword', 'How do I change my password in GitLab?'), translate('GlDuoChat.chatDefaultPredefinedPromptsForkProject', 'How do I fork a project?'), translate('GlDuoChat.chatDefaultPredefinedPromptsCloneRepository', 'How do I clone a repository?'), translate('GlDuoChat.chatDefaultPredefinedPromptsCreateTemplate', 'How do I create a template?')]
40
- };
41
- const isMessage = item => Boolean(item) && (item === null || item === void 0 ? void 0 : item.role);
42
- const isSlashCommand = command => Boolean(command) && (command === null || command === void 0 ? void 0 : command.name) && command.description;
43
-
44
- // eslint-disable-next-line unicorn/no-array-callback-reference
45
- const itemsValidator = items => items.every(isMessage);
46
- // eslint-disable-next-line unicorn/no-array-callback-reference
47
- const slashCommandsValidator = commands => commands.every(isSlashCommand);
48
- var script = {
49
- name: 'GlDuoChat',
50
- components: {
51
- GlEmptyState,
52
- GlButton,
53
- GlAlert,
54
- GlFormInputGroup,
55
- GlFormTextarea,
56
- GlForm,
57
- GlExperimentBadge,
58
- GlDuoChatLoader,
59
- GlDuoChatPredefinedPrompts,
60
- GlDuoChatConversation,
61
- GlCard,
62
- GlDropdownItem
63
- },
64
- directives: {
65
- SafeHtml: SafeHtmlDirective
66
- },
67
- props: {
68
- /**
69
- * The title of the chat/feature.
70
- */
71
- title: {
72
- type: String,
73
- required: false,
74
- default: i18n.CHAT_DEFAULT_TITLE
75
- },
76
- /**
77
- * Array of messages to display in the chat.
78
- */
79
- messages: {
80
- type: Array,
81
- required: false,
82
- default: () => [],
83
- validator: itemsValidator
84
- },
85
- /**
86
- * Array of RequestIds that have been canceled.
87
- */
88
- canceledRequestIds: {
89
- type: Array,
90
- required: false,
91
- default: () => []
92
- },
93
- /**
94
- * A non-recoverable error message to display in the chat.
95
- */
96
- error: {
97
- type: String,
98
- required: false,
99
- default: ''
100
- },
101
- /**
102
- * Whether the chat is currently fetching a response from AI.
103
- */
104
- isLoading: {
105
- type: Boolean,
106
- required: false,
107
- default: false
108
- },
109
- /**
110
- * Whether the conversational interfaces should be enabled.
111
- */
112
- isChatAvailable: {
113
- type: Boolean,
114
- required: false,
115
- default: true
116
- },
117
- /**
118
- * Whether the insertCode feature should be available.
119
- */
120
- enableCodeInsertion: {
121
- type: Boolean,
122
- required: false,
123
- default: false
124
- },
125
- /**
126
- * Array of predefined prompts to display in the chat to start a conversation.
127
- */
128
- predefinedPrompts: {
129
- type: Array,
130
- required: false,
131
- default: () => i18n.CHAT_DEFAULT_PREDEFINED_PROMPTS
132
- },
133
- /**
134
- * URL to the help page. This is passed down to the `GlExperimentBadge` component.
135
- */
136
- badgeHelpPageUrl: {
137
- type: String,
138
- required: false,
139
- default: ''
140
- },
141
- /**
142
- * The type of the badge. This is passed down to the `GlExperimentBadge` component. Refer that component for more information.
143
- */
144
- badgeType: {
145
- type: String || null,
146
- required: false,
147
- default: badgeTypes[0],
148
- validator: badgeTypeValidator
149
- },
150
- /**
151
- * The current tool's name to display in the loading message while waiting for a response from AI. Refer the `GlDuoChatLoader` component for more information.
152
- */
153
- toolName: {
154
- type: String,
155
- required: false,
156
- default: i18n.CHAT_DEFAULT_TITLE
157
- },
158
- /**
159
- * Array of slash commands to display in the chat.
160
- */
161
- slashCommands: {
162
- type: Array,
163
- required: false,
164
- default: () => [],
165
- validator: slashCommandsValidator
166
- },
167
- /**
168
- * Whether the header should be displayed.
169
- */
170
- showHeader: {
171
- type: Boolean,
172
- required: false,
173
- default: true
174
- },
175
- /**
176
- * Override the default empty state title text.
177
- */
178
- emptyStateTitle: {
179
- type: String,
180
- required: false,
181
- default: i18n.CHAT_EMPTY_STATE_TITLE
182
- },
183
- /**
184
- * Override the default empty state description text.
185
- */
186
- emptyStateDescription: {
187
- type: String,
188
- required: false,
189
- default: i18n.CHAT_EMPTY_STATE_DESC
190
- },
191
- /**
192
- * Override the default empty state description secondary text.
193
- */
194
- emptyStateSecondaryDescription: {
195
- type: String,
196
- required: false,
197
- default: i18n.CHAT_EMPTY_STATE_SECONDARY_DESC
198
- },
199
- /**
200
- * Override the default chat prompt placeholder text.
201
- */
202
- chatPromptPlaceholder: {
203
- type: String,
204
- required: false,
205
- default: ''
206
- }
207
- },
208
- data() {
209
- return {
210
- isHidden: false,
211
- prompt: '',
212
- scrolledToBottom: true,
213
- activeCommandIndex: 0,
214
- displaySubmitButton: true,
215
- compositionJustEnded: false,
216
- contextItemsMenuIsOpen: false,
217
- contextItemMenuRef: null
218
- };
219
- },
220
- computed: {
221
- withSlashCommands() {
222
- return this.slashCommands.length > 0;
223
- },
224
- hasMessages() {
225
- var _this$messages;
226
- return ((_this$messages = this.messages) === null || _this$messages === void 0 ? void 0 : _this$messages.length) > 0;
227
- },
228
- conversations() {
229
- if (!this.hasMessages) return [];
230
- return this.messages.reduce((acc, message) => {
231
- if (message.content === CHAT_RESET_MESSAGE) {
232
- acc.push([]);
233
- } else {
234
- acc[acc.length - 1].push(message);
235
- }
236
- return acc;
237
- }, [[]]);
238
- },
239
- lastMessage() {
240
- var _this$messages2;
241
- return (_this$messages2 = this.messages) === null || _this$messages2 === void 0 ? void 0 : _this$messages2[this.messages.length - 1];
242
- },
243
- caseInsensitivePrompt() {
244
- return this.prompt.toLowerCase().trim();
245
- },
246
- resetDisabled() {
247
- var _this$lastMessage;
248
- if (this.isLoading || !this.hasMessages) {
249
- return true;
250
- }
251
- return ((_this$lastMessage = this.lastMessage) === null || _this$lastMessage === void 0 ? void 0 : _this$lastMessage.content) === CHAT_RESET_MESSAGE;
252
- },
253
- isStreaming() {
254
- var _this$lastMessage2, _this$lastMessage3, _this$lastMessage3$ch, _this$lastMessage4, _this$lastMessage5;
255
- if (this.canceledRequestIds.includes((_this$lastMessage2 = this.lastMessage) === null || _this$lastMessage2 === void 0 ? void 0 : _this$lastMessage2.requestId)) {
256
- return false;
257
- }
258
- return Boolean(((_this$lastMessage3 = this.lastMessage) === null || _this$lastMessage3 === void 0 ? void 0 : (_this$lastMessage3$ch = _this$lastMessage3.chunks) === null || _this$lastMessage3$ch === void 0 ? void 0 : _this$lastMessage3$ch.length) > 0 && !((_this$lastMessage4 = this.lastMessage) !== null && _this$lastMessage4 !== void 0 && _this$lastMessage4.content) || typeof ((_this$lastMessage5 = this.lastMessage) === null || _this$lastMessage5 === void 0 ? void 0 : _this$lastMessage5.chunkId) === 'number');
259
- },
260
- filteredSlashCommands() {
261
- return this.slashCommands.filter(c => c.name.toLowerCase().startsWith(this.caseInsensitivePrompt)).filter(c => {
262
- if (c.name === CHAT_INCLUDE_MESSAGE) {
263
- return this.hasContextItemSelectionMenu;
264
- }
265
- return true;
266
- });
267
- },
268
- shouldShowSlashCommands() {
269
- if (!this.withSlashCommands || this.contextItemsMenuIsOpen) return false;
270
- const startsWithSlash = this.caseInsensitivePrompt.startsWith('/');
271
- const startsWithSlashCommand = this.slashCommands.some(c => this.caseInsensitivePrompt.startsWith(c.name));
272
- return startsWithSlash && this.filteredSlashCommands.length && !startsWithSlashCommand;
273
- },
274
- shouldShowContextItemSelectionMenu() {
275
- if (!this.hasContextItemSelectionMenu) {
276
- return false;
277
- }
278
- const isSlash = this.caseInsensitivePrompt === '/';
279
- if (!this.caseInsensitivePrompt || isSlash) {
280
- // if user has removed entire command (or whole command except for '/') we should close context item menu and allow slash command menu to show again
281
- return false;
282
- }
283
- return CHAT_INCLUDE_MESSAGE.startsWith(this.caseInsensitivePrompt);
284
- },
285
- inputPlaceholder() {
286
- if (this.chatPromptPlaceholder) {
287
- return this.chatPromptPlaceholder;
288
- }
289
- return this.withSlashCommands ? i18n.CHAT_PROMPT_PLACEHOLDER_WITH_COMMANDS : i18n.CHAT_PROMPT_PLACEHOLDER_DEFAULT;
290
- },
291
- hasContextItemSelectionMenu() {
292
- return Boolean(this.contextItemMenuRef);
293
- }
294
- },
295
- watch: {
296
- isLoading(newVal) {
297
- if (!newVal && !this.isStreaming) {
298
- this.displaySubmitButton = true; // Re-enable submit button when loading stops
299
- }
300
- this.isHidden = false;
301
- },
302
- isStreaming(newVal) {
303
- if (!newVal && !this.isLoading) {
304
- this.displaySubmitButton = true; // Re-enable submit button when streaming stops
305
- }
306
- },
307
- lastMessage(newMessage) {
308
- if (this.scrolledToBottom || newMessage.role.toLowerCase() === MESSAGE_MODEL_ROLES.user) {
309
- // only scroll to bottom on new message if the user hasn't explicitly scrolled up to view an earlier message
310
- // or if the user has just submitted a new message
311
- this.scrollToBottom();
312
- }
313
- },
314
- shouldShowSlashCommands(shouldShow) {
315
- if (shouldShow) {
316
- this.onShowSlashCommands();
317
- }
318
- }
319
- },
320
- created() {
321
- this.handleScrollingTrottled = throttle(this.handleScrolling, 200); // Assume a 200ms throttle for example
322
- },
323
- mounted() {
324
- this.scrollToBottom();
325
- },
326
- methods: {
327
- compositionEnd() {
328
- this.compositionJustEnded = true;
329
- },
330
- hideChat() {
331
- this.isHidden = true;
332
- /**
333
- * Emitted when clicking the cross in the title and the chat gets closed.
334
- */
335
- this.$emit('chat-hidden');
336
- },
337
- cancelPrompt() {
338
- /**
339
- * Emitted when user clicks the stop button in the textarea
340
- */
341
-
342
- this.displaySubmitButton = true;
343
- this.$emit('chat-cancel');
344
- this.setPromptAndFocus();
345
- },
346
- sendChatPrompt() {
347
- if (!this.displaySubmitButton || this.contextItemsMenuIsOpen) {
348
- return;
349
- }
350
- if (this.prompt) {
351
- if (this.caseInsensitivePrompt === CHAT_RESET_MESSAGE && this.resetDisabled) {
352
- return;
353
- }
354
- if (this.caseInsensitivePrompt.startsWith(CHAT_INCLUDE_MESSAGE) && this.hasContextItemSelectionMenu) {
355
- this.contextItemsMenuIsOpen = true;
356
- return;
357
- }
358
- if (![CHAT_RESET_MESSAGE, CHAT_CLEAR_MESSAGE].includes(this.caseInsensitivePrompt)) {
359
- this.displaySubmitButton = false;
360
- }
361
-
362
- /**
363
- * Emitted when a new user prompt should be sent out.
364
- *
365
- * @param {String} prompt The user prompt to send.
366
- */
367
- this.$emit('send-chat-prompt', this.prompt.trim());
368
- this.setPromptAndFocus();
369
- }
370
- },
371
- sendPredefinedPrompt(prompt) {
372
- this.contextItemsMenuIsOpen = false;
373
- this.prompt = prompt;
374
- this.sendChatPrompt();
375
- },
376
- handleScrolling(event) {
377
- const {
378
- scrollTop,
379
- offsetHeight,
380
- scrollHeight
381
- } = event.target;
382
- this.scrolledToBottom = scrollTop + offsetHeight >= scrollHeight;
383
- },
384
- async scrollToBottom() {
385
- var _this$$refs$anchor, _this$$refs$anchor$sc;
386
- await this.$nextTick();
387
- (_this$$refs$anchor = this.$refs.anchor) === null || _this$$refs$anchor === void 0 ? void 0 : (_this$$refs$anchor$sc = _this$$refs$anchor.scrollIntoView) === null || _this$$refs$anchor$sc === void 0 ? void 0 : _this$$refs$anchor$sc.call(_this$$refs$anchor);
388
- },
389
- focusChatInput() {
390
- var _this$$refs$prompt, _this$$refs$prompt$$e;
391
- // This method is also called directly by consumers of this component
392
- // https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/blob/dae2d4669ab4da327921492a2962beae8a05c290/webviews/vue2/gitlab_duo_chat/src/App.vue#L109
393
- (_this$$refs$prompt = this.$refs.prompt) === null || _this$$refs$prompt === void 0 ? void 0 : (_this$$refs$prompt$$e = _this$$refs$prompt.$el) === null || _this$$refs$prompt$$e === void 0 ? void 0 : _this$$refs$prompt$$e.focus();
394
- },
395
- onTrackFeedback(event) {
396
- /**
397
- * Notify listeners about the feedback form submission on a response message.
398
- * @param {*} event An event, containing the feedback choices and the extended feedback text.
399
- */
400
- this.$emit('track-feedback', event);
401
- },
402
- onShowSlashCommands() {
403
- /**
404
- * Emitted when user opens the slash commands menu
405
- */
406
- this.$emit('chat-slash');
407
- },
408
- sendChatPromptOnEnter(e) {
409
- const {
410
- metaKey,
411
- ctrlKey,
412
- altKey,
413
- shiftKey,
414
- isComposing
415
- } = e;
416
- const isModifierKey = metaKey || ctrlKey || altKey || shiftKey;
417
- return !(isModifierKey || isComposing || this.compositionJustEnded);
418
- },
419
- onInputKeyup(e) {
420
- const {
421
- key
422
- } = e;
423
- if (this.contextItemsMenuIsOpen) {
424
- var _this$contextItemMenu;
425
- if (!this.shouldShowContextItemSelectionMenu) {
426
- this.contextItemsMenuIsOpen = false;
427
- }
428
- (_this$contextItemMenu = this.contextItemMenuRef) === null || _this$contextItemMenu === void 0 ? void 0 : _this$contextItemMenu.handleKeyUp(e);
429
- return;
430
- }
431
- if (this.caseInsensitivePrompt === CHAT_INCLUDE_MESSAGE) {
432
- this.contextItemsMenuIsOpen = true;
433
- return;
434
- }
435
- if (this.shouldShowSlashCommands) {
436
- e.preventDefault();
437
- if (key === 'Enter') {
438
- this.selectSlashCommand(this.activeCommandIndex);
439
- } else if (key === 'ArrowUp') {
440
- this.prevCommand();
441
- } else if (key === 'ArrowDown') {
442
- this.nextCommand();
443
- } else {
444
- this.activeCommandIndex = 0;
445
- }
446
- } else if (key === 'Enter' && this.sendChatPromptOnEnter(e)) {
447
- e.preventDefault();
448
- this.sendChatPrompt();
449
- }
450
- this.compositionJustEnded = false;
451
- },
452
- prevCommand() {
453
- this.activeCommandIndex -= 1;
454
- this.wrapCommandIndex();
455
- },
456
- nextCommand() {
457
- this.activeCommandIndex += 1;
458
- this.wrapCommandIndex();
459
- },
460
- wrapCommandIndex() {
461
- if (this.activeCommandIndex < 0) {
462
- this.activeCommandIndex = this.filteredSlashCommands.length - 1;
463
- } else if (this.activeCommandIndex >= this.filteredSlashCommands.length) {
464
- this.activeCommandIndex = 0;
465
- }
466
- },
467
- async setPromptAndFocus() {
468
- let prompt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
469
- this.prompt = prompt;
470
- await this.$nextTick();
471
- this.focusChatInput();
472
- },
473
- selectSlashCommand(index) {
474
- const command = this.filteredSlashCommands[index];
475
- if (command.shouldSubmit) {
476
- this.prompt = command.name;
477
- this.sendChatPrompt();
478
- } else {
479
- this.setPromptAndFocus(`${command.name} `);
480
- if (command.name === CHAT_INCLUDE_MESSAGE && this.hasContextItemSelectionMenu) {
481
- this.contextItemsMenuIsOpen = true;
482
- }
483
- }
484
- },
485
- onInsertCodeSnippet(e) {
486
- /**
487
- * Emit insert-code-snippet event that clients can use to interact with a suggested code.
488
- * @param {*} event An event containing code string in the "detail.code" field.
489
- */
490
- this.$emit('insert-code-snippet', e);
491
- },
492
- onGetContextItemContent(event) {
493
- /**
494
- * Emit get-context-item-content event that tells clients to load the full file content for a selected context item.
495
- * The fully hydrated context item should be updated in the chat message context item.
496
- * @param {*} event An event containing the message ID and context item to hydrate
497
- */
498
- this.$emit('get-context-item-content', event);
499
- },
500
- closeContextItemsMenuOpen() {
501
- this.contextItemsMenuIsOpen = false;
502
- this.setPromptAndFocus();
503
- },
504
- setContextItemsMenuRef(ref) {
505
- this.contextItemMenuRef = ref;
506
- }
507
- },
508
- i18n,
509
- emptySvg
510
- };
511
-
512
- /* script */
513
- const __vue_script__ = script;
514
-
515
- /* template */
516
- var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return (!_vm.isHidden)?_c('aside',{staticClass:"markdown-code-block duo-chat-drawer duo-chat gl-bottom-0 gl-max-h-full",attrs:{"id":"chat-component","role":"complementary","data-testid":"chat-component"}},[(_vm.showHeader)?_c('header',{staticClass:"duo-chat-drawer-header duo-chat-drawer-header-sticky gl-z-200 gl-border-0 gl-bg-default !gl-p-0",attrs:{"data-testid":"chat-header"}},[_c('div',{staticClass:"drawer-title gl-flex gl-items-center gl-justify-start gl-p-5"},[_c('h3',{staticClass:"gl-my-0 gl-text-size-h2"},[_vm._v(_vm._s(_vm.title))]),_vm._v(" "),(_vm.badgeType)?_c('gl-experiment-badge',{attrs:{"help-page-url":_vm.badgeHelpPageUrl,"type":_vm.badgeType,"container-id":"chat-component"}}):_vm._e(),_vm._v(" "),_c('gl-button',{staticClass:"gl-ml-auto",attrs:{"category":"tertiary","variant":"default","icon":"close","size":"small","data-testid":"chat-close-button","aria-label":_vm.$options.i18n.CHAT_CLOSE_LABEL},on:{"click":_vm.hideChat}})],1),_vm._v(" "),_vm._t("subheader"),_vm._v(" "),(_vm.error)?_c('gl-alert',{key:"error",staticClass:"!gl-pl-9",attrs:{"dismissible":false,"variant":"danger","role":"alert","data-testid":"chat-error"}},[_c('span',{directives:[{name:"safe-html",rawName:"v-safe-html",value:(_vm.error),expression:"error"}]})]):_vm._e()],2):_vm._e(),_vm._v(" "),_c('div',{staticClass:"duo-chat-drawer-body gl-bg-default",attrs:{"data-testid":"chat-history"},on:{"scroll":_vm.handleScrollingTrottled}},[_c('transition-group',{staticClass:"duo-chat-history gl-flex gl-flex-col gl-justify-end",class:[
517
- {
518
- 'gl-h-full': !_vm.hasMessages,
519
- 'force-scroll-bar': _vm.hasMessages,
520
- } ],attrs:{"tag":"section","name":"message"}},[_vm._l((_vm.conversations),function(conversation,index){return _c('gl-duo-chat-conversation',{key:("conversation-" + index),attrs:{"enable-code-insertion":_vm.enableCodeInsertion,"messages":conversation,"canceled-request-ids":_vm.canceledRequestIds,"show-delimiter":index > 0},on:{"track-feedback":_vm.onTrackFeedback,"insert-code-snippet":_vm.onInsertCodeSnippet,"get-context-item-content":_vm.onGetContextItemContent}})}),_vm._v(" "),(!_vm.hasMessages && !_vm.isLoading)?[_c('gl-empty-state',{key:"empty-state",staticClass:"gl-flex-grow gl-justify-center",attrs:{"svg-path":_vm.$options.emptySvg,"svg-height":145,"title":_vm.emptyStateTitle},scopedSlots:_vm._u([{key:"description",fn:function(){return [_c('p',{staticClass:"gl-mb-3",attrs:{"data-testid":"gl-duo-chat-empty-state-description"}},[_vm._v("\n "+_vm._s(_vm.emptyStateDescription)+"\n ")]),_vm._v(" "),_c('p',{staticClass:"gl-mt-3 gl-text-sm gl-text-subtle",attrs:{"data-testid":"gl-duo-chat-empty-state-secondary-description"}},[_vm._v("\n "+_vm._s(_vm.emptyStateSecondaryDescription)+"\n ")])]},proxy:true}],null,false,460840487)}),_vm._v(" "),_c('gl-duo-chat-predefined-prompts',{key:"predefined-prompts",attrs:{"prompts":_vm.predefinedPrompts},on:{"click":_vm.sendPredefinedPrompt}})]:_vm._e(),_vm._v(" "),(_vm.isLoading)?_c('gl-duo-chat-loader',{key:"loader",attrs:{"tool-name":_vm.toolName}}):_vm._e(),_vm._v(" "),_c('div',{key:"anchor",ref:"anchor",staticClass:"scroll-anchor"})],2)],1),_vm._v(" "),(_vm.isChatAvailable)?_c('footer',{staticClass:"duo-chat-drawer-footer duo-chat-drawer-footer-sticky gl-border-0 gl-bg-default gl-p-5",class:{ 'duo-chat-drawer-body-scrim-on-footer': !_vm.scrolledToBottom },attrs:{"data-testid":"chat-footer"}},[_c('gl-form',{attrs:{"data-testid":"chat-prompt-form"},on:{"submit":function($event){$event.stopPropagation();$event.preventDefault();return _vm.sendChatPrompt.apply(null, arguments)}}},[_c('div',{staticClass:"gl-relative gl-max-w-full"},[_vm._t("context-items-menu",null,{"isOpen":_vm.contextItemsMenuIsOpen,"onClose":_vm.closeContextItemsMenuOpen,"setRef":_vm.setContextItemsMenuRef,"focusPrompt":_vm.focusChatInput})],2),_vm._v(" "),_c('gl-form-input-group',{scopedSlots:_vm._u([{key:"append",fn:function(){return [(_vm.displaySubmitButton)?_c('gl-button',{staticClass:"!gl-absolute gl-bottom-2 gl-right-2 !gl-rounded-full",attrs:{"icon":"paper-airplane","category":"primary","variant":"confirm","type":"submit","data-testid":"chat-prompt-submit-button","aria-label":_vm.$options.i18n.CHAT_SUBMIT_LABEL}}):_c('gl-button',{staticClass:"!gl-absolute gl-bottom-2 gl-right-2 !gl-rounded-full",attrs:{"icon":"stop","category":"primary","variant":"default","data-testid":"chat-prompt-cancel-button","aria-label":_vm.$options.i18n.CHAT_CANCEL_LABEL},on:{"click":_vm.cancelPrompt}})]},proxy:true}],null,false,608602988)},[_c('div',{staticClass:"duo-chat-input gl-min-h-8 gl-max-w-full gl-grow gl-align-top",attrs:{"data-value":_vm.prompt}},[(_vm.shouldShowSlashCommands)?_c('gl-card',{ref:"commands",staticClass:"slash-commands !gl-absolute gl-w-full -gl-translate-y-full gl-list-none gl-pl-0 gl-shadow-md",attrs:{"body-class":"!gl-p-2"}},_vm._l((_vm.filteredSlashCommands),function(command,index){return _c('gl-dropdown-item',{key:command.name,class:{ 'active-command': index === _vm.activeCommandIndex },on:{"click":function($event){return _vm.selectSlashCommand(index)}},nativeOn:{"mouseenter":function($event){_vm.activeCommandIndex = index;}}},[_c('span',{staticClass:"gl-flex gl-justify-between"},[_c('span',{staticClass:"gl-block"},[_vm._v(_vm._s(command.name))]),_vm._v(" "),_c('small',{staticClass:"gl-pl-3 gl-text-right gl-italic gl-text-subtle"},[_vm._v(_vm._s(command.description))])])])}),1):_vm._e(),_vm._v(" "),_c('gl-form-textarea',{ref:"prompt",staticClass:"gl-absolute !gl-h-full gl-rounded-br-none gl-rounded-tr-none !gl-bg-transparent !gl-py-4 !gl-shadow-none",class:{ 'gl-truncate': !_vm.prompt },attrs:{"data-testid":"chat-prompt-input","placeholder":_vm.inputPlaceholder,"autofocus":""},on:{"compositionend":_vm.compositionEnd},nativeOn:{"keydown":function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"enter",13,$event.key,"Enter")){ return null; }if($event.ctrlKey||$event.shiftKey||$event.altKey||$event.metaKey){ return null; }$event.preventDefault();},"keyup":function($event){return _vm.onInputKeyup.apply(null, arguments)}},model:{value:(_vm.prompt),callback:function ($$v) {_vm.prompt=$$v;},expression:"prompt"}})],1)])],1)],1):_vm._e()]):_vm._e()};
521
- var __vue_staticRenderFns__ = [];
522
-
523
- /* style */
524
- const __vue_inject_styles__ = undefined;
525
- /* scoped */
526
- const __vue_scope_id__ = undefined;
527
- /* module identifier */
528
- const __vue_module_identifier__ = undefined;
529
- /* functional template */
530
- const __vue_is_functional_template__ = false;
531
- /* style inject */
532
-
533
- /* style inject SSR */
534
-
535
- /* style inject shadow dom */
536
-
537
-
538
-
539
- const __vue_component__ = __vue_normalize__(
540
- { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
541
- __vue_inject_styles__,
542
- __vue_script__,
543
- __vue_scope_id__,
544
- __vue_is_functional_template__,
545
- __vue_module_identifier__,
546
- false,
547
- undefined,
548
- undefined,
549
- undefined
550
- );
551
-
552
- export default __vue_component__;
553
- export { i18n };
@@ -1,25 +0,0 @@
1
- import { Marked } from 'marked';
2
- import markedBidi from 'marked-bidi';
3
-
4
- /**
5
- * This component has been migrated to the Duo-UI library (https://gitlab.com/gitlab-org/duo-ui).
6
- *
7
- * Please use the corresponding component in Duo-UI going forward.
8
- * All future development and maintenance for Duo components should take place in Duo-UI.
9
- *
10
- * For more details, see the migration epic: https://gitlab.com/groups/gitlab-org/-/epics/15344 or reach out to the Duo-Chat team in #g_duo_chat.
11
- */
12
- const duoMarked = new Marked([{
13
- async: false,
14
- breaks: false,
15
- gfm: false
16
- }, markedBidi()]);
17
- function renderDuoChatMarkdownPreview(md) {
18
- try {
19
- return md ? duoMarked.parse(md.toString()) : '';
20
- } catch {
21
- return md;
22
- }
23
- }
24
-
25
- export { renderDuoChatMarkdownPreview };