@gitlab/duo-ui 8.2.1 → 8.4.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/CHANGELOG.md CHANGED
@@ -1,3 +1,38 @@
1
+ # [8.4.0](https://gitlab.com/gitlab-org/duo-ui/compare/v8.3.0...v8.4.0) (2025-02-28)
2
+
3
+
4
+ ### Features
5
+
6
+ * add support for duo chat multithreading ([7f10c77](https://gitlab.com/gitlab-org/duo-ui/commit/7f10c77f4ed28b869a749317f5278c384cd653b3))
7
+
8
+ # [8.4.0](https://gitlab.com/gitlab-org/duo-ui/compare/v8.3.0...v8.4.0) (2025-02-28)
9
+
10
+
11
+ ### Features
12
+
13
+ * add support for duo chat multithreading ([7f10c77](https://gitlab.com/gitlab-org/duo-ui/commit/7f10c77f4ed28b869a749317f5278c384cd653b3))
14
+
15
+ # [8.4.0](https://gitlab.com/gitlab-org/duo-ui/compare/v8.3.0...v8.4.0) (2025-02-27)
16
+
17
+
18
+ ### Features
19
+
20
+ * add support for duo chat multithreading ([7f10c77](https://gitlab.com/gitlab-org/duo-ui/commit/7f10c77f4ed28b869a749317f5278c384cd653b3))
21
+
22
+ # [8.4.0](https://gitlab.com/gitlab-org/duo-ui/compare/v8.3.0...v8.4.0) (2025-02-27)
23
+
24
+
25
+ ### Features
26
+
27
+ * add support for duo chat multithreading ([7f10c77](https://gitlab.com/gitlab-org/duo-ui/commit/7f10c77f4ed28b869a749317f5278c384cd653b3))
28
+
29
+ # [8.3.0](https://gitlab.com/gitlab-org/duo-ui/compare/v8.2.1...v8.3.0) (2025-02-21)
30
+
31
+
32
+ ### Features
33
+
34
+ * add Duo Chat header component ([b120863](https://gitlab.com/gitlab-org/duo-ui/commit/b12086344411a02894ddca77c3be9c7763443ce6))
35
+
1
36
  ## [8.2.1](https://gitlab.com/gitlab-org/duo-ui/compare/v8.2.0...v8.2.1) (2025-02-21)
2
37
 
3
38
 
@@ -0,0 +1,6 @@
1
+ const VIEW_TYPES = {
2
+ CHAT: 'chat',
3
+ LIST: 'list'
4
+ };
5
+
6
+ export { VIEW_TYPES };
@@ -0,0 +1,106 @@
1
+ import { GlButton, GlAlert, GlExperimentBadge, GlSafeHtmlDirective } from '@gitlab/ui';
2
+ import { translate } from '../../../../utils/i18n';
3
+ import { VIEW_TYPES } from './constants';
4
+ import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
5
+
6
+ const i18n = {
7
+ CHAT_BACK_LABEL: translate('DuoChat.chatBackLabel', 'Back to History'),
8
+ CHAT_CLOSE_LABEL: translate('DuoChat.closeChatHeaderLabel', 'Close Chat'),
9
+ CHAT_NEW_LABEL: translate('DuoChat.chatNewLabel', 'New Chat'),
10
+ CHAT_TITLE: translate('DuoChat.chatTitle', 'GitLab Duo Chat')
11
+ };
12
+ var script = {
13
+ name: 'DuoChatHeader',
14
+ components: {
15
+ GlButton,
16
+ GlAlert,
17
+ GlExperimentBadge
18
+ },
19
+ directives: {
20
+ SafeHtml: GlSafeHtmlDirective
21
+ },
22
+ props: {
23
+ title: {
24
+ type: String,
25
+ required: false,
26
+ default: i18n.CHAT_TITLE
27
+ },
28
+ error: {
29
+ type: String,
30
+ required: false,
31
+ default: ''
32
+ },
33
+ isMultithreaded: {
34
+ type: Boolean,
35
+ required: false,
36
+ default: false
37
+ },
38
+ shouldRenderResizable: {
39
+ type: Boolean,
40
+ required: false,
41
+ default: false
42
+ },
43
+ activeThreadId: {
44
+ type: String,
45
+ required: false,
46
+ default: null
47
+ },
48
+ badgeType: {
49
+ type: String,
50
+ required: false,
51
+ default: null
52
+ },
53
+ currentView: {
54
+ type: String,
55
+ required: true
56
+ }
57
+ },
58
+ computed: {
59
+ VIEW_TYPES() {
60
+ return VIEW_TYPES;
61
+ }
62
+ },
63
+ i18n
64
+ };
65
+
66
+ /* script */
67
+ const __vue_script__ = script;
68
+
69
+ /* template */
70
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('header',{staticClass:"duo-chat-drawer-header duo-chat-drawer-header-sticky gl-border-0 gl-bg-default !gl-p-0",class:{
71
+ 'gl-z-200': !_vm.shouldRenderResizable,
72
+ 'gl-z-1': _vm.shouldRenderResizable,
73
+ },attrs:{"data-testid":"chat-header"}},[_c('div',{staticClass:"drawer-title gl-flex gl-items-center gl-justify-start gl-p-5"},[(_vm.isMultithreaded && _vm.currentView === _vm.VIEW_TYPES.CHAT)?_c('gl-button',{staticClass:"gl-mr-3",attrs:{"data-testid":"chat-back-button","category":"primary","size":"medium","icon":"history","aria-label":_vm.$options.i18n.CHAT_BACK_LABEL},on:{"click":function($event){return _vm.$emit('go-back')}}}):_vm._e(),_vm._v(" "),(_vm.isMultithreaded && (_vm.activeThreadId || _vm.currentView === _vm.VIEW_TYPES.LIST))?_c('gl-button',{staticClass:"gl-mr-3",attrs:{"data-testid":"chat-new-button","category":"primary","size":"medium","icon":"duo-chat-new","aria-label":_vm.$options.i18n.CHAT_NEW_LABEL},on:{"click":function($event){return _vm.$emit('new-chat')}}}):_vm._e(),_vm._v(" "),_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:{"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":function($event){return _vm.$emit('close')}}})],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)};
74
+ var __vue_staticRenderFns__ = [];
75
+
76
+ /* style */
77
+ const __vue_inject_styles__ = undefined;
78
+ /* scoped */
79
+ const __vue_scope_id__ = undefined;
80
+ /* module identifier */
81
+ const __vue_module_identifier__ = undefined;
82
+ /* functional template */
83
+ const __vue_is_functional_template__ = false;
84
+ /* style inject */
85
+
86
+ /* style inject SSR */
87
+
88
+ /* style inject shadow dom */
89
+
90
+
91
+
92
+ const __vue_component__ = __vue_normalize__(
93
+ { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
94
+ __vue_inject_styles__,
95
+ __vue_script__,
96
+ __vue_scope_id__,
97
+ __vue_is_functional_template__,
98
+ __vue_module_identifier__,
99
+ false,
100
+ undefined,
101
+ undefined,
102
+ undefined
103
+ );
104
+
105
+ export default __vue_component__;
106
+ export { i18n };
@@ -0,0 +1,96 @@
1
+ import { GlButton, GlIcon } from '@gitlab/ui';
2
+ import { translate } from '../../../../utils/i18n';
3
+ import { formatDate } from '../../../../utils/date';
4
+ import DuoChatThreadsEmpty from './duo_chat_threads_empty';
5
+ import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
6
+
7
+ const i18n = {
8
+ CHAT_HISTORY_INFO: translate('DuoChat.chatHistoryInfo', 'Chats with no activity in the last 30 days are deleted.'),
9
+ THREAD_DELETE_LABEL: translate('DuoChat.threadDeleteLabel', 'Delete this thread.')
10
+ };
11
+ var script = {
12
+ name: 'DuoChatHistory',
13
+ components: {
14
+ GlButton,
15
+ GlIcon,
16
+ DuoChatThreadsEmpty
17
+ },
18
+ props: {
19
+ threads: {
20
+ type: Array,
21
+ required: true
22
+ }
23
+ },
24
+ computed: {
25
+ formatDate() {
26
+ return formatDate;
27
+ },
28
+ groupedThreads() {
29
+ return this.threads.reduce((threadsGroupedByDate, thread) => {
30
+ const date = new Date(thread.createdAt);
31
+ const dateKey = date.toISOString().split('T')[0];
32
+ return {
33
+ ...threadsGroupedByDate,
34
+ [dateKey]: [...(threadsGroupedByDate[dateKey] || []), thread]
35
+ };
36
+ }, {});
37
+ },
38
+ hasThreads() {
39
+ return this.threads.length > 0;
40
+ }
41
+ },
42
+ methods: {
43
+ onNewChat() {
44
+ this.$emit('new-chat');
45
+ },
46
+ onSelectThread(thread) {
47
+ this.$emit('select-thread', thread);
48
+ },
49
+ onDeleteThread(threadId, event) {
50
+ event.stopPropagation();
51
+ this.$emit('delete-thread', threadId);
52
+ },
53
+ onClose() {
54
+ this.$emit('close');
55
+ }
56
+ },
57
+ i18n
58
+ };
59
+
60
+ /* script */
61
+ const __vue_script__ = script;
62
+
63
+ /* template */
64
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"gl-h-full gl-p-5"},[_c('div',{staticClass:"gl-bg-gray-50 gl-text-gray-500 gl-p-4 gl-mb-5 gl-rounded-base",attrs:{"data-testid":"chat-threads-info-banner"}},[_c('p',{staticClass:"gl-m-0 gl-flex"},[_c('gl-icon',{staticClass:"gl-mr-4",attrs:{"name":"bulb"}}),_vm._v(_vm._s(_vm.$options.i18n.CHAT_HISTORY_INFO)+"\n ")],1)]),_vm._v(" "),(_vm.hasThreads)?_vm._l((_vm.groupedThreads),function(threadsForDate,date){return _c('div',{key:date},[_c('div',{staticClass:"gl-font-bold gl-neutral-900 gl-mb-4",attrs:{"data-testid":"chat-threads-date-header"}},[_vm._v("\n "+_vm._s(_vm.formatDate(date))+"\n ")]),_vm._v(" "),_c('div',_vm._l((threadsForDate),function(thread){return _c('div',{key:thread.id,staticClass:"gl-flex gl-align-center gl-mb-4"},[_c('div',{staticClass:"thread-box hover:gl-bg-gray-50 focus:gl-bg-gray-50 gl-text-ellipsis gl-overflow-hidden gl-rounded-base gl-cursor-pointer gl-rounded-base gl-p-4 gl-w-full gl-whitespace-nowrap",attrs:{"tabindex":"0","data-testid":"chat-threads-thread-box"},on:{"click":function($event){return _vm.onSelectThread(thread)}}},[_vm._v("\n "+_vm._s(thread.title || 'Untitled Chat')+"\n ")]),_vm._v(" "),_c('gl-button',{staticClass:"gl-neutral-900 !gl-p-4",attrs:{"data-testid":"chat-threads-delete-thread-button","icon":"remove","category":"tertiary","size":"small","aria-label":_vm.$options.i18n.THREAD_DELETE_LABEL},on:{"click":function($event){return _vm.$emit('delete-thread', thread.id)}}})],1)}),0)])}):_c('duo-chat-threads-empty')],2)};
65
+ var __vue_staticRenderFns__ = [];
66
+
67
+ /* style */
68
+ const __vue_inject_styles__ = undefined;
69
+ /* scoped */
70
+ const __vue_scope_id__ = undefined;
71
+ /* module identifier */
72
+ const __vue_module_identifier__ = undefined;
73
+ /* functional template */
74
+ const __vue_is_functional_template__ = false;
75
+ /* style inject */
76
+
77
+ /* style inject SSR */
78
+
79
+ /* style inject shadow dom */
80
+
81
+
82
+
83
+ const __vue_component__ = __vue_normalize__(
84
+ { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
85
+ __vue_inject_styles__,
86
+ __vue_script__,
87
+ __vue_scope_id__,
88
+ __vue_is_functional_template__,
89
+ __vue_module_identifier__,
90
+ false,
91
+ undefined,
92
+ undefined,
93
+ undefined
94
+ );
95
+
96
+ export default __vue_component__;
@@ -0,0 +1,52 @@
1
+ import ScheduleIllustration from '@gitlab/svgs/dist/illustrations/schedule-md.svg';
2
+ import { translate } from '../../../../utils/i18n';
3
+ import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
4
+
5
+ const i18n = {
6
+ EMPTY_HISTORY_TITLE: translate('DuoChat.emptyHistoryTitle', 'See your chat history'),
7
+ EMPTY_HISTORY_COPY: translate('DuoChat.emptyHistoryCopy', 'Your previous chats will appear here.'),
8
+ EMPTY_HISTORY_ALT: translate('DuoChat.emptyHistoryAlt', 'Clock icon with circular arrow, indicating chat history or time-based functionality')
9
+ };
10
+ var script = {
11
+ name: 'DuoChatHistoryEmpty',
12
+ i18n,
13
+ ScheduleIllustration
14
+ };
15
+
16
+ /* script */
17
+ const __vue_script__ = script;
18
+
19
+ /* template */
20
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"gl-h-full gl-flex gl-flex-col gl-align-center gl-items-center gl-justify-center"},[_c('img',{staticClass:"gl-mb-5",attrs:{"src":_vm.$options.ScheduleIllustration,"alt":_vm.$options.i18n.EMPTY_HISTORY_ALT,"data-testid":"empty-state-illustration"}}),_vm._v(" "),_c('h3',{staticClass:"gl-font-bold gl-neutral-900 gl-mb-4",attrs:{"data-testid":"empty-state-title"}},[_vm._v("\n "+_vm._s(_vm.$options.i18n.EMPTY_HISTORY_TITLE)+"\n ")]),_vm._v(" "),_c('p',{staticClass:"gl-align-center",attrs:{"data-testid":"empty-state-description"}},[_vm._v("\n "+_vm._s(_vm.$options.i18n.EMPTY_HISTORY_COPY)+"\n ")])])};
21
+ var __vue_staticRenderFns__ = [];
22
+
23
+ /* style */
24
+ const __vue_inject_styles__ = undefined;
25
+ /* scoped */
26
+ const __vue_scope_id__ = undefined;
27
+ /* module identifier */
28
+ const __vue_module_identifier__ = undefined;
29
+ /* functional template */
30
+ const __vue_is_functional_template__ = false;
31
+ /* style inject */
32
+
33
+ /* style inject SSR */
34
+
35
+ /* style inject shadow dom */
36
+
37
+
38
+
39
+ const __vue_component__ = __vue_normalize__(
40
+ { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
41
+ __vue_inject_styles__,
42
+ __vue_script__,
43
+ __vue_scope_id__,
44
+ __vue_is_functional_template__,
45
+ __vue_module_identifier__,
46
+ false,
47
+ undefined,
48
+ undefined,
49
+ undefined
50
+ );
51
+
52
+ export default __vue_component__;
@@ -3,15 +3,18 @@ import VueResizable from 'vue-resizable';
3
3
  import { GlButton, GlAlert, GlFormInputGroup, GlFormTextarea, GlForm, GlExperimentBadge, GlCard, GlDropdownItem, GlSafeHtmlDirective } from '@gitlab/ui';
4
4
  import { translate } from '../../utils/i18n';
5
5
  import { badgeTypes, badgeTypeValidator, CHAT_RESET_MESSAGE, CHAT_INCLUDE_MESSAGE, MESSAGE_MODEL_ROLES, CHAT_CLEAR_MESSAGE, CHAT_NEW_MESSAGE } from './constants';
6
+ import { VIEW_TYPES } from './components/duo_chat_header/constants';
6
7
  import DuoChatLoader from './components/duo_chat_loader/duo_chat_loader';
7
8
  import DuoChatPredefinedPrompts from './components/duo_chat_predefined_prompts/duo_chat_predefined_prompts';
8
9
  import DuoChatConversation from './components/duo_chat_conversation/duo_chat_conversation';
10
+ import DuoChatHeader from './components/duo_chat_header/duo_chat_header';
11
+ import DuoChatThreads from './components/duo_chat_threads/duo_chat_threads';
9
12
  import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
10
13
 
11
14
  const i18n = {
12
15
  CHAT_DEFAULT_TITLE: translate('DuoChat.chatDefaultTitle', 'GitLab Duo Chat'),
16
+ CHAT_HISTORY_TITLE: translate('GlDuoChat.chatHistoryTitle', 'Chat history'),
13
17
  CHAT_DISCLAMER: translate('GlDuoChat.chatDisclamer', 'Responses may be inaccurate. Verify before use.'),
14
- CHAT_CLOSE_LABEL: translate('DuoChat.chatCloseLabel', 'Close the Code Explanation'),
15
18
  CHAT_EMPTY_STATE_TITLE: translate('DuoChat.chatEmptyStateTitle', '👋 I am GitLab Duo Chat, your personal AI-powered assistant. How can I help you today?'),
16
19
  CHAT_PROMPT_PLACEHOLDER_DEFAULT: translate('DuoChat.chatPromptPlaceholderDefault', 'GitLab Duo Chat'),
17
20
  CHAT_PROMPT_PLACEHOLDER_WITH_COMMANDS: translate('DuoChat.chatPromptPlaceholderWithCommands', 'Type /help to learn more'),
@@ -26,6 +29,10 @@ const isSlashCommand = command => Boolean(command) && (command === null || comma
26
29
  const itemsValidator = items => items.every(isMessage);
27
30
  // eslint-disable-next-line unicorn/no-array-callback-reference
28
31
  const slashCommandsValidator = commands => commands.every(isSlashCommand);
32
+ const isThread = thread => typeof thread === 'object' && typeof thread.id === 'string' && typeof thread.lastUpdatedAt === 'string' && typeof thread.createdAt === 'string' && typeof thread.conversationType === 'string' && (thread.title === null || typeof thread.title === 'string');
33
+
34
+ // eslint-disable-next-line unicorn/no-array-callback-reference
35
+ const threadListValidator = threads => threads.every(isThread);
29
36
  var script = {
30
37
  name: 'DuoChat',
31
38
  components: {
@@ -38,6 +45,8 @@ var script = {
38
45
  DuoChatLoader,
39
46
  DuoChatPredefinedPrompts,
40
47
  DuoChatConversation,
48
+ DuoChatHeader,
49
+ DuoChatThreads,
41
50
  GlCard,
42
51
  GlDropdownItem,
43
52
  VueResizable
@@ -92,6 +101,23 @@ var script = {
92
101
  default: () => [],
93
102
  validator: itemsValidator
94
103
  },
104
+ /**
105
+ * The ID of the active thread (if any).
106
+ */
107
+ activeThreadId: {
108
+ type: String,
109
+ required: false,
110
+ default: () => ''
111
+ },
112
+ /**
113
+ * The chat page that should be shown.
114
+ */
115
+ multiThreadedView: {
116
+ type: String,
117
+ required: false,
118
+ default: VIEW_TYPES.LIST,
119
+ validator: value => [VIEW_TYPES.LIST, VIEW_TYPES.CHAT].includes(value)
120
+ },
95
121
  /**
96
122
  * Array of RequestIds that have been canceled.
97
123
  */
@@ -108,6 +134,15 @@ var script = {
108
134
  required: false,
109
135
  default: ''
110
136
  },
137
+ /**
138
+ * Array of messages to display in the chat.
139
+ */
140
+ threadList: {
141
+ type: Array,
142
+ required: false,
143
+ default: () => [],
144
+ validator: threadListValidator
145
+ },
111
146
  /**
112
147
  * Whether the chat is currently fetching a response from AI.
113
148
  */
@@ -189,6 +224,14 @@ var script = {
189
224
  type: String,
190
225
  required: false,
191
226
  default: ''
227
+ },
228
+ /**
229
+ * Whether the chat is running in multi-threaded mode
230
+ */
231
+ isMultithreaded: {
232
+ type: Boolean,
233
+ required: false,
234
+ default: false
192
235
  }
193
236
  },
194
237
  data() {
@@ -200,10 +243,14 @@ var script = {
200
243
  displaySubmitButton: true,
201
244
  compositionJustEnded: false,
202
245
  contextItemsMenuIsOpen: false,
203
- contextItemMenuRef: null
246
+ contextItemMenuRef: null,
247
+ currentView: this.multiThreadedView
204
248
  };
205
249
  },
206
250
  computed: {
251
+ shouldShowThreadList() {
252
+ return this.isMultithreaded && this.currentView === VIEW_TYPES.LIST;
253
+ },
207
254
  withSlashCommands() {
208
255
  return this.slashCommands.length > 0;
209
256
  },
@@ -272,6 +319,9 @@ var script = {
272
319
  }
273
320
  },
274
321
  watch: {
322
+ multiThreadedView(newView) {
323
+ this.currentView = newView;
324
+ },
275
325
  isLoading(newVal) {
276
326
  if (!newVal && !this.isStreaming) {
277
327
  this.displaySubmitButton = true; // Re-enable submit button when loading stops
@@ -303,6 +353,12 @@ var script = {
303
353
  this.scrollToBottom();
304
354
  },
305
355
  methods: {
356
+ onGoBack() {
357
+ this.$emit('back-to-list');
358
+ },
359
+ onNewChat() {
360
+ this.$emit('new-chat');
361
+ },
306
362
  updateSize(e) {
307
363
  this.$emit('chat-resize', e);
308
364
  },
@@ -489,6 +545,20 @@ var script = {
489
545
  },
490
546
  setContextItemsMenuRef(ref) {
491
547
  this.contextItemMenuRef = ref;
548
+ },
549
+ onSelectThread(thread) {
550
+ /**
551
+ * Emitted when a thread is selected from the history.
552
+ * @param {Object} thread The selected thread object
553
+ */
554
+ this.$emit('thread-selected', thread);
555
+ },
556
+ onDeleteThread(threadId) {
557
+ /**
558
+ * Emitted when a thread is deleted from the history.
559
+ * @param {String} threadId The ID of the thread to delete
560
+ */
561
+ this.$emit('delete-thread', threadId);
492
562
  }
493
563
  },
494
564
  i18n
@@ -504,13 +574,11 @@ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=
504
574
  },attrs:{"width":_vm.shouldRenderResizable ? _vm.dimensions.width : null,"height":_vm.shouldRenderResizable ? _vm.dimensions.height : null,"max-width":_vm.shouldRenderResizable ? _vm.dimensions.maxWidth : null,"max-height":_vm.shouldRenderResizable ? _vm.dimensions.maxHeight : null,"min-width":_vm.shouldRenderResizable ? _vm.dimensions.minWidth : null,"left":_vm.shouldRenderResizable ? _vm.dimensions.left : null,"top":_vm.shouldRenderResizable ? _vm.dimensions.top : null,"fit-parent":true,"min-height":_vm.shouldRenderResizable ? _vm.dimensions.minHeight : null,"active":_vm.shouldRenderResizable ? ['l', 't', 'lt'] : null},on:{"resize:end":_vm.updateSize}},[(!_vm.isHidden)?_c('aside',{staticClass:"markdown-code-block duo-chat gl-bottom-0 gl-max-h-full",class:{
505
575
  'resizable-content': _vm.shouldRenderResizable,
506
576
  'duo-chat-drawer': !_vm.shouldRenderResizable,
507
- },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-border-0 gl-bg-default !gl-p-0",class:{
508
- 'gl-z-200': !_vm.shouldRenderResizable,
509
- },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:{"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:[
510
- {
511
- 'gl-h-full': !_vm.hasMessages,
512
- 'force-scroll-bar': _vm.hasMessages,
513
- } ],attrs:{"tag":"section","name":"message"}},[_vm._l((_vm.conversations),function(conversation,index){return _c('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,"copy-code-snippet":_vm.onCopyCodeSnippet,"get-context-item-content":_vm.onGetContextItemContent}})}),_vm._v(" "),(!_vm.hasMessages && !_vm.isLoading)?[_c('div',{key:"empty-state-message",staticClass:"duo-chat-message gl-rounded-bl-none gl-border-1 gl-border-solid gl-border-subtle gl-bg-subtle gl-p-4 gl-leading-20 gl-text-primary gl-break-anywhere",attrs:{"data-testid":"gl-duo-chat-empty-state"}},[(_vm.emptyStateTitle)?_c('p',{staticClass:"gl-m-0",attrs:{"data-testid":"gl-duo-chat-empty-state-title"}},[_vm._v("\n "+_vm._s(_vm.emptyStateTitle)+"\n ")]):_vm._e(),_vm._v(" "),_c('duo-chat-predefined-prompts',{key:"predefined-prompts",attrs:{"prompts":_vm.predefinedPrompts},on:{"click":_vm.sendPredefinedPrompt}})],1)]:_vm._e(),_vm._v(" "),(_vm.isLoading)?_c('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-pb-3",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),_vm._v(" "),_c('p',{staticClass:"gl-mb-0 gl-mt-3 gl-px-4 gl-text-sm gl-text-secondary"},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CHAT_DISCLAMER)+"\n ")])],1):_vm._e()]):_vm._e()])};
577
+ },attrs:{"id":"chat-component","role":"complementary","data-testid":"chat-component"}},[(_vm.showHeader)?_c('duo-chat-header',{attrs:{"active-thread-id":_vm.activeThreadId,"title":_vm.isMultithreaded && _vm.currentView === 'list' ? _vm.$options.i18n.CHAT_HISTORY_TITLE : _vm.title,"error":_vm.error,"is-multithreaded":_vm.isMultithreaded,"current-view":_vm.currentView,"should-render-resizable":_vm.shouldRenderResizable,"badge-type":_vm.isMultithreaded ? null : _vm.badgeType},on:{"go-back":_vm.onGoBack,"new-chat":_vm.onNewChat,"close":_vm.hideChat},scopedSlots:_vm._u([{key:"subheader",fn:function(){return [_vm._t("subheader")]},proxy:true}],null,true)}):_vm._e(),_vm._v(" "),(_vm.shouldShowThreadList)?_c('div',{staticClass:"gl-h-full"},[_c('duo-chat-threads',{attrs:{"threads":_vm.threadList},on:{"new-chat":_vm.onNewChat,"select-thread":_vm.onSelectThread,"delete-thread":_vm.onDeleteThread,"close":_vm.hideChat}})],1):_c('span',{staticClass:"gl-h-full gl-flex gl-flex-col gl-justify-end"},[_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:[
578
+ {
579
+ 'gl-h-full': !_vm.hasMessages,
580
+ 'force-scroll-bar': _vm.hasMessages,
581
+ } ],attrs:{"tag":"section","name":"message"}},[_vm._l((_vm.conversations),function(conversation,index){return _c('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,"copy-code-snippet":_vm.onCopyCodeSnippet,"get-context-item-content":_vm.onGetContextItemContent}})}),_vm._v(" "),(!_vm.hasMessages && !_vm.isLoading)?[_c('div',{key:"empty-state-message",staticClass:"duo-chat-message gl-rounded-bl-none gl-border-1 gl-border-solid gl-border-gray-50 gl-bg-gray-10 gl-p-4 gl-leading-20 gl-text-gray-900 gl-break-anywhere",attrs:{"data-testid":"gl-duo-chat-empty-state"}},[(_vm.emptyStateTitle)?_c('p',{staticClass:"gl-m-0",attrs:{"data-testid":"gl-duo-chat-empty-state-title"}},[_vm._v("\n "+_vm._s(_vm.emptyStateTitle)+"\n ")]):_vm._e(),_vm._v(" "),_c('duo-chat-predefined-prompts',{key:"predefined-prompts",attrs:{"prompts":_vm.predefinedPrompts},on:{"click":_vm.sendPredefinedPrompt}})],1)]:_vm._e(),_vm._v(" "),(_vm.isLoading)?_c('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-pb-3",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),_vm._v(" "),_c('p',{staticClass:"gl-mb-0 gl-mt-3 gl-px-4 gl-text-sm gl-text-secondary"},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CHAT_DISCLAMER)+"\n ")])],1):_vm._e()])],1):_vm._e()])};
514
582
  var __vue_staticRenderFns__ = [];
515
583
 
516
584
  /* style */
@@ -158,5 +158,76 @@ const INCLUDE_SLASH_COMMAND = {
158
158
  name: CHAT_INCLUDE_MESSAGE,
159
159
  description: 'Include additional context in the conversation.'
160
160
  };
161
+ const THREADLIST = [{
162
+ __typename: 'AiConversationsThread',
163
+ id: 'gid://gitlab/Ai::Conversation::Thread/14',
164
+ lastUpdatedAt: '2025-01-31T11:12:05Z',
165
+ createdAt: '2025-01-31T11:12:00Z',
166
+ conversationType: 'DUO_CHAT',
167
+ title: 'On the Proper Filing of Form B-789 in Triplicate'
168
+ }, {
169
+ __typename: 'AiConversationsThread',
170
+ id: 'gid://gitlab/Ai::Conversation::Thread/13',
171
+ lastUpdatedAt: '2025-01-31T14:30:42Z',
172
+ createdAt: '2025-01-31T14:30:36Z',
173
+ conversationType: 'DUO_CHAT',
174
+ title: 'The Case of the Missing Permission Slip'
175
+ }, {
176
+ __typename: 'AiConversationsThread',
177
+ id: 'gid://gitlab/Ai::Conversation::Thread/12',
178
+ lastUpdatedAt: '2025-01-31T14:30:08Z',
179
+ createdAt: '2025-01-31T14:30:03Z',
180
+ conversationType: 'DUO_CHAT',
181
+ title: 'Regarding the Metamorphosis of Code Review #2187'
182
+ }, {
183
+ __typename: 'AiConversationsThread',
184
+ id: 'gid://gitlab/Ai::Conversation::Thread/11',
185
+ lastUpdatedAt: '2025-01-24T14:29:51Z',
186
+ createdAt: '2025-01-24T14:29:36Z',
187
+ conversationType: 'DUO_CHAT',
188
+ title: "An Investigation into the Disappearance of Yesterday's Commits"
189
+ }, {
190
+ __typename: 'AiConversationsThread',
191
+ id: 'gid://gitlab/Ai::Conversation::Thread/10',
192
+ lastUpdatedAt: '2025-01-24T14:29:25Z',
193
+ createdAt: '2025-01-24T14:28:50Z',
194
+ conversationType: 'DUO_CHAT',
195
+ title: 'The Curious Incident of the Bug in the Runtime'
196
+ }, {
197
+ __typename: 'AiConversationsThread',
198
+ id: 'gid://gitlab/Ai::Conversation::Thread/9',
199
+ lastUpdatedAt: '2025-01-15T14:24:30Z',
200
+ createdAt: '2025-01-15T14:24:26Z',
201
+ conversationType: 'DUO_CHAT',
202
+ title: 'Notes on the Inexplicable Behavior of the Legacy System'
203
+ }, {
204
+ __typename: 'AiConversationsThread',
205
+ id: 'gid://gitlab/Ai::Conversation::Thread/8',
206
+ lastUpdatedAt: '2025-01-15T14:24:21Z',
207
+ createdAt: '2025-01-15T14:24:17Z',
208
+ conversationType: 'DUO_CHAT',
209
+ title: 'The Trial of the Undefined Variable'
210
+ }, {
211
+ __typename: 'AiConversationsThread',
212
+ id: 'gid://gitlab/Ai::Conversation::Thread/7',
213
+ lastUpdatedAt: '2025-01-15T14:12:13Z',
214
+ createdAt: '2025-01-15T14:12:08Z',
215
+ conversationType: 'DUO_CHAT',
216
+ title: 'Waiting for the Database Response'
217
+ }, {
218
+ __typename: 'AiConversationsThread',
219
+ id: 'gid://gitlab/Ai::Conversation::Thread/6',
220
+ lastUpdatedAt: '2025-01-08T14:11:46Z',
221
+ createdAt: '2025-01-08T14:11:38Z',
222
+ conversationType: 'DUO_CHAT',
223
+ title: 'The Endless Corridor of Dependencies'
224
+ }, {
225
+ __typename: 'AiConversationsThread',
226
+ id: 'gid://gitlab/Ai::Conversation::Thread/5',
227
+ lastUpdatedAt: '2025-01-08T14:11:24Z',
228
+ createdAt: '2025-01-08T14:11:24Z',
229
+ conversationType: 'DUO_CHAT',
230
+ title: 'Before the Configuration Committee'
231
+ }];
161
232
 
162
- export { INCLUDE_SLASH_COMMAND, MOCK_RESPONSE_MESSAGE, MOCK_RESPONSE_MESSAGE_FOR_STREAMING, MOCK_USER_PROMPT_MESSAGE, SLASH_COMMANDS, generateMockResponseChunks, generateSeparateChunks, renderGFM, renderMarkdown };
233
+ export { INCLUDE_SLASH_COMMAND, MOCK_RESPONSE_MESSAGE, MOCK_RESPONSE_MESSAGE_FOR_STREAMING, MOCK_USER_PROMPT_MESSAGE, SLASH_COMMANDS, THREADLIST, generateMockResponseChunks, generateSeparateChunks, renderGFM, renderMarkdown };