@gitlab/ui 92.0.0 → 92.1.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 +7 -0
- package/dist/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu.js +5 -0
- package/dist/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_selections/duo_chat_context_item_selections.js +1 -1
- package/dist/components/experimental/duo/chat/constants.js +2 -1
- package/dist/components/experimental/duo/chat/duo_chat.js +65 -15
- package/dist/components/experimental/duo/chat/mock_data.js +6 -2
- package/dist/index.js +1 -0
- package/package.json +1 -1
- package/src/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu.vue +5 -0
- package/src/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_selections/duo_chat_context_item_selections.vue +1 -0
- package/src/components/experimental/duo/chat/constants.js +1 -0
- package/src/components/experimental/duo/chat/duo_chat.vue +95 -15
- package/src/components/experimental/duo/chat/mock_data.js +6 -0
- package/src/index.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [92.1.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v92.0.0...v92.1.0) (2024-09-10)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **GlDuoChat:** add /include command, integrate context-item-menu ([3f664f8](https://gitlab.com/gitlab-org/gitlab-ui/commit/3f664f89a35aa426bb043f1563cd2bdb9722878c))
|
|
7
|
+
|
|
1
8
|
# [92.0.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v91.15.0...v92.0.0) (2024-09-10)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -82,7 +82,7 @@ var script = {
|
|
|
82
82
|
const __vue_script__ = script;
|
|
83
83
|
|
|
84
84
|
/* template */
|
|
85
|
-
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"gl-mb-3 gl-flex gl-flex-col"},[_c('button',{staticClass:"gl-flex gl-w-full gl-items-center gl-border-0 gl-bg-transparent gl-p-0 gl-text-left gl-text-xs gl-lowercase gl-text-gray-500",attrs:{"data-testid":"chat-context-selections-title"},on:{"click":_vm.toggleCollapse}},[_c('gl-icon',{attrs:{"name":_vm.collapseIconName,"data-testid":"chat-context-collapse-icon"}}),_vm._v(" "+_vm._s(_vm.title)+"\n ")],1),_vm._v(" "),_c('div',{directives:[{name:"show",rawName:"v-show",value:(!_vm.isCollapsed),expression:"!isCollapsed"}],staticClass:"gl-mt-1 gl-flex gl-grow gl-flex-wrap",attrs:{"data-testid":"chat-context-tokens-wrapper"}},_vm._l((_vm.selections),function(contextItem){return _c('gl-token',{key:contextItem.id,staticClass:"gl-mb-2 gl-mr-2",attrs:{"view-only":!_vm.removable,"variant":"default"},on:{"close":function($event){return _vm.onRemoveItem(contextItem)}}},[_c('div',{staticClass:"gl-flex gl-items-center",attrs:{"id":("context-item-" + (contextItem.id) + "-" + _vm.selectionsId)}},[_c('gl-icon',{staticClass:"gl-mr-1",attrs:{"name":_vm.getIconName(contextItem.type),"size":12}}),_vm._v("\n "+_vm._s(contextItem.metadata.name)+"\n ")],1),_vm._v(" "),_c('gl-duo-chat-context-item-popover',{attrs:{"context-item":contextItem,"target":("context-item-" + (contextItem.id) + "-" + _vm.selectionsId),"placement":"bottom"}})],1)}),1)])};
|
|
85
|
+
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"gl-mb-3 gl-flex gl-flex-col"},[_c('button',{staticClass:"gl-flex gl-w-full gl-items-center gl-border-0 gl-bg-transparent gl-p-0 gl-text-left gl-text-xs gl-lowercase gl-text-gray-500",attrs:{"data-testid":"chat-context-selections-title","type":"button"},on:{"click":_vm.toggleCollapse}},[_c('gl-icon',{attrs:{"name":_vm.collapseIconName,"data-testid":"chat-context-collapse-icon"}}),_vm._v(" "+_vm._s(_vm.title)+"\n ")],1),_vm._v(" "),_c('div',{directives:[{name:"show",rawName:"v-show",value:(!_vm.isCollapsed),expression:"!isCollapsed"}],staticClass:"gl-mt-1 gl-flex gl-grow gl-flex-wrap",attrs:{"data-testid":"chat-context-tokens-wrapper"}},_vm._l((_vm.selections),function(contextItem){return _c('gl-token',{key:contextItem.id,staticClass:"gl-mb-2 gl-mr-2",attrs:{"view-only":!_vm.removable,"variant":"default"},on:{"close":function($event){return _vm.onRemoveItem(contextItem)}}},[_c('div',{staticClass:"gl-flex gl-items-center",attrs:{"id":("context-item-" + (contextItem.id) + "-" + _vm.selectionsId)}},[_c('gl-icon',{staticClass:"gl-mr-1",attrs:{"name":_vm.getIconName(contextItem.type),"size":12}}),_vm._v("\n "+_vm._s(contextItem.metadata.name)+"\n ")],1),_vm._v(" "),_c('gl-duo-chat-context-item-popover',{attrs:{"context-item":contextItem,"target":("context-item-" + (contextItem.id) + "-" + _vm.selectionsId),"placement":"bottom"}})],1)}),1)])};
|
|
86
86
|
var __vue_staticRenderFns__ = [];
|
|
87
87
|
|
|
88
88
|
/* style */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const CHAT_RESET_MESSAGE = '/reset';
|
|
2
2
|
const CHAT_CLEAN_MESSAGE = '/clean';
|
|
3
3
|
const CHAT_CLEAR_MESSAGE = '/clear';
|
|
4
|
+
const CHAT_INCLUDE_MESSAGE = '/include';
|
|
4
5
|
const LOADING_TRANSITION_DURATION = 7500;
|
|
5
6
|
const DOCUMENTATION_SOURCE_TYPES = {
|
|
6
7
|
HANDBOOK: {
|
|
@@ -22,4 +23,4 @@ const MESSAGE_MODEL_ROLES = {
|
|
|
22
23
|
assistant: 'assistant'
|
|
23
24
|
};
|
|
24
25
|
|
|
25
|
-
export { CHAT_CLEAN_MESSAGE, CHAT_CLEAR_MESSAGE, CHAT_RESET_MESSAGE, DOCUMENTATION_SOURCE_TYPES, LOADING_TRANSITION_DURATION, MESSAGE_MODEL_ROLES };
|
|
26
|
+
export { CHAT_CLEAN_MESSAGE, CHAT_CLEAR_MESSAGE, CHAT_INCLUDE_MESSAGE, CHAT_RESET_MESSAGE, DOCUMENTATION_SOURCE_TYPES, LOADING_TRANSITION_DURATION, MESSAGE_MODEL_ROLES };
|
|
@@ -14,7 +14,8 @@ import { SafeHtmlDirective } from '../../../../directives/safe_html/safe_html';
|
|
|
14
14
|
import GlDuoChatLoader from './components/duo_chat_loader/duo_chat_loader';
|
|
15
15
|
import GlDuoChatPredefinedPrompts from './components/duo_chat_predefined_prompts/duo_chat_predefined_prompts';
|
|
16
16
|
import GlDuoChatConversation from './components/duo_chat_conversation/duo_chat_conversation';
|
|
17
|
-
import { CHAT_RESET_MESSAGE, CHAT_CLEAN_MESSAGE, CHAT_CLEAR_MESSAGE } from './constants';
|
|
17
|
+
import { CHAT_RESET_MESSAGE, CHAT_INCLUDE_MESSAGE, CHAT_CLEAN_MESSAGE, CHAT_CLEAR_MESSAGE } from './constants';
|
|
18
|
+
import { INCLUDE_SLASH_COMMAND } from './mock_data';
|
|
18
19
|
import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
|
|
19
20
|
|
|
20
21
|
const i18n = {
|
|
@@ -205,7 +206,9 @@ var script = {
|
|
|
205
206
|
scrolledToBottom: true,
|
|
206
207
|
activeCommandIndex: 0,
|
|
207
208
|
displaySubmitButton: true,
|
|
208
|
-
compositionJustEnded: false
|
|
209
|
+
compositionJustEnded: false,
|
|
210
|
+
contextItemsMenuIsOpen: false,
|
|
211
|
+
contextItemMenuRef: null
|
|
209
212
|
};
|
|
210
213
|
},
|
|
211
214
|
computed: {
|
|
@@ -231,6 +234,9 @@ var script = {
|
|
|
231
234
|
var _this$messages2;
|
|
232
235
|
return (_this$messages2 = this.messages) === null || _this$messages2 === void 0 ? void 0 : _this$messages2[this.messages.length - 1];
|
|
233
236
|
},
|
|
237
|
+
caseInsensitivePrompt() {
|
|
238
|
+
return this.prompt.toLowerCase().trim();
|
|
239
|
+
},
|
|
234
240
|
resetDisabled() {
|
|
235
241
|
var _this$lastMessage;
|
|
236
242
|
if (this.isLoading || !this.hasMessages) {
|
|
@@ -246,21 +252,38 @@ var script = {
|
|
|
246
252
|
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');
|
|
247
253
|
},
|
|
248
254
|
filteredSlashCommands() {
|
|
249
|
-
|
|
250
|
-
|
|
255
|
+
return this.slashCommands.filter(c => c.name.toLowerCase().startsWith(this.caseInsensitivePrompt)).filter(c => {
|
|
256
|
+
if (c.name === CHAT_INCLUDE_MESSAGE) {
|
|
257
|
+
return this.hasContextItemSelectionMenu;
|
|
258
|
+
}
|
|
259
|
+
return true;
|
|
260
|
+
});
|
|
251
261
|
},
|
|
252
262
|
shouldShowSlashCommands() {
|
|
253
|
-
if (!this.withSlashCommands) return false;
|
|
254
|
-
const
|
|
255
|
-
const
|
|
256
|
-
const startsWithSlashCommand = this.slashCommands.some(c => caseInsensitivePrompt.startsWith(c.name));
|
|
263
|
+
if (!this.withSlashCommands || this.contextItemsMenuIsOpen) return false;
|
|
264
|
+
const startsWithSlash = this.caseInsensitivePrompt.startsWith('/');
|
|
265
|
+
const startsWithSlashCommand = this.slashCommands.some(c => this.caseInsensitivePrompt.startsWith(c.name));
|
|
257
266
|
return startsWithSlash && this.filteredSlashCommands.length && !startsWithSlashCommand;
|
|
258
267
|
},
|
|
268
|
+
shouldShowContextItemSelectionMenu() {
|
|
269
|
+
if (!this.hasContextItemSelectionMenu) {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
const isSlash = this.caseInsensitivePrompt === '/';
|
|
273
|
+
if (!this.caseInsensitivePrompt || isSlash) {
|
|
274
|
+
// 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
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
return INCLUDE_SLASH_COMMAND.name.startsWith(this.caseInsensitivePrompt);
|
|
278
|
+
},
|
|
259
279
|
inputPlaceholder() {
|
|
260
280
|
if (this.chatPromptPlaceholder) {
|
|
261
281
|
return this.chatPromptPlaceholder;
|
|
262
282
|
}
|
|
263
283
|
return this.withSlashCommands ? i18n.CHAT_PROMPT_PLACEHOLDER_WITH_COMMANDS : i18n.CHAT_PROMPT_PLACEHOLDER_DEFAULT;
|
|
284
|
+
},
|
|
285
|
+
hasContextItemSelectionMenu() {
|
|
286
|
+
return Boolean(this.contextItemMenuRef);
|
|
264
287
|
}
|
|
265
288
|
},
|
|
266
289
|
watch: {
|
|
@@ -304,27 +327,32 @@ var script = {
|
|
|
304
327
|
this.setPromptAndFocus();
|
|
305
328
|
},
|
|
306
329
|
sendChatPrompt() {
|
|
307
|
-
if (!this.displaySubmitButton) {
|
|
330
|
+
if (!this.displaySubmitButton || this.contextItemsMenuIsOpen) {
|
|
308
331
|
return;
|
|
309
332
|
}
|
|
310
333
|
if (this.prompt) {
|
|
311
|
-
if (this.
|
|
334
|
+
if (this.caseInsensitivePrompt === CHAT_RESET_MESSAGE && this.resetDisabled) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (this.caseInsensitivePrompt.startsWith(CHAT_INCLUDE_MESSAGE) && this.hasContextItemSelectionMenu) {
|
|
338
|
+
this.contextItemsMenuIsOpen = true;
|
|
312
339
|
return;
|
|
313
340
|
}
|
|
341
|
+
if (![CHAT_RESET_MESSAGE, CHAT_CLEAN_MESSAGE, CHAT_CLEAR_MESSAGE].includes(this.caseInsensitivePrompt)) {
|
|
342
|
+
this.displaySubmitButton = false;
|
|
343
|
+
}
|
|
344
|
+
|
|
314
345
|
/**
|
|
315
346
|
* Emitted when a new user prompt should be sent out.
|
|
316
347
|
*
|
|
317
348
|
* @param {String} prompt The user prompt to send.
|
|
318
349
|
*/
|
|
319
|
-
|
|
320
|
-
if (![CHAT_RESET_MESSAGE, CHAT_CLEAN_MESSAGE, CHAT_CLEAR_MESSAGE].includes(this.prompt)) {
|
|
321
|
-
this.displaySubmitButton = false;
|
|
322
|
-
}
|
|
323
350
|
this.$emit('send-chat-prompt', this.prompt.trim());
|
|
324
351
|
this.setPromptAndFocus();
|
|
325
352
|
}
|
|
326
353
|
},
|
|
327
354
|
sendPredefinedPrompt(prompt) {
|
|
355
|
+
this.contextItemsMenuIsOpen = false;
|
|
328
356
|
this.prompt = prompt;
|
|
329
357
|
this.sendChatPrompt();
|
|
330
358
|
},
|
|
@@ -371,6 +399,18 @@ var script = {
|
|
|
371
399
|
const {
|
|
372
400
|
key
|
|
373
401
|
} = e;
|
|
402
|
+
if (this.contextItemsMenuIsOpen) {
|
|
403
|
+
var _this$contextItemMenu;
|
|
404
|
+
if (!this.shouldShowContextItemSelectionMenu) {
|
|
405
|
+
this.contextItemsMenuIsOpen = false;
|
|
406
|
+
}
|
|
407
|
+
(_this$contextItemMenu = this.contextItemMenuRef) === null || _this$contextItemMenu === void 0 ? void 0 : _this$contextItemMenu.handleKeyUp(e);
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
if (this.caseInsensitivePrompt === INCLUDE_SLASH_COMMAND.name) {
|
|
411
|
+
this.contextItemsMenuIsOpen = true;
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
374
414
|
if (this.shouldShowSlashCommands) {
|
|
375
415
|
e.preventDefault();
|
|
376
416
|
if (key === 'Enter') {
|
|
@@ -416,6 +456,9 @@ var script = {
|
|
|
416
456
|
this.sendChatPrompt();
|
|
417
457
|
} else {
|
|
418
458
|
this.setPromptAndFocus(`${command.name} `);
|
|
459
|
+
if (command.name === CHAT_INCLUDE_MESSAGE && this.hasContextItemSelectionMenu) {
|
|
460
|
+
this.contextItemsMenuIsOpen = true;
|
|
461
|
+
}
|
|
419
462
|
}
|
|
420
463
|
},
|
|
421
464
|
onInsertCodeSnippet(e) {
|
|
@@ -424,6 +467,13 @@ var script = {
|
|
|
424
467
|
* @param {*} event An event containing code string in the "detail.code" field.
|
|
425
468
|
*/
|
|
426
469
|
this.$emit('insert-code-snippet', e);
|
|
470
|
+
},
|
|
471
|
+
closeContextItemsMenuOpen() {
|
|
472
|
+
this.contextItemsMenuIsOpen = false;
|
|
473
|
+
this.setPromptAndFocus();
|
|
474
|
+
},
|
|
475
|
+
setContextItemsMenuRef(ref) {
|
|
476
|
+
this.contextItemMenuRef = ref;
|
|
427
477
|
}
|
|
428
478
|
},
|
|
429
479
|
i18n,
|
|
@@ -438,7 +488,7 @@ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=
|
|
|
438
488
|
{
|
|
439
489
|
'gl-h-full': !_vm.hasMessages,
|
|
440
490
|
'force-scroll-bar': _vm.hasMessages,
|
|
441
|
-
} ],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}})}),_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-t gl-bg-gray-10 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('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-base",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-base",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,677611116)},[_c('div',{staticClass:"duo-chat-input gl-min-h-8 gl-max-w-full gl-grow gl-rounded-base gl-bg-white gl-align-top gl-shadow-inner-1-gray-400",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-gray-500"},[_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)]),_vm._v(" "),_c('p',{staticClass:"gl-mb-0 gl-mt-3 gl-text-sm gl-leading-20 gl-text-subtle",attrs:{"data-testid":"chat-legal-disclaimer"}},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CHAT_LEGAL_DISCLAIMER)+"\n ")])],1)],1):_vm._e()]):_vm._e()};
|
|
491
|
+
} ],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}})}),_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-t gl-bg-gray-10 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-base",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-base",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,677611116)},[_c('div',{staticClass:"duo-chat-input gl-min-h-8 gl-max-w-full gl-grow gl-rounded-base gl-bg-white gl-align-top gl-shadow-inner-1-gray-400",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-gray-500"},[_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)]),_vm._v(" "),_c('p',{staticClass:"gl-mb-0 gl-mt-3 gl-text-sm gl-leading-20 gl-text-subtle",attrs:{"data-testid":"chat-legal-disclaimer"}},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CHAT_LEGAL_DISCLAIMER)+"\n ")])],1)],1):_vm._e()]):_vm._e()};
|
|
442
492
|
var __vue_staticRenderFns__ = [];
|
|
443
493
|
|
|
444
494
|
/* style */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { setStoryTimeout } from '../../../../utils/test_utils';
|
|
2
|
-
import { DOCUMENTATION_SOURCE_TYPES, MESSAGE_MODEL_ROLES, CHAT_RESET_MESSAGE, CHAT_CLEAN_MESSAGE } from './constants';
|
|
2
|
+
import { DOCUMENTATION_SOURCE_TYPES, MESSAGE_MODEL_ROLES, CHAT_RESET_MESSAGE, CHAT_CLEAN_MESSAGE, CHAT_INCLUDE_MESSAGE } from './constants';
|
|
3
3
|
import { getMockContextItems } from './components/duo_chat_context/mock_context_data';
|
|
4
4
|
|
|
5
5
|
const MOCK_SOURCES = [{
|
|
@@ -154,5 +154,9 @@ const SLASH_COMMANDS = [{
|
|
|
154
154
|
name: '/explain',
|
|
155
155
|
description: 'Explain the selected snippet.'
|
|
156
156
|
}];
|
|
157
|
+
const INCLUDE_SLASH_COMMAND = {
|
|
158
|
+
name: CHAT_INCLUDE_MESSAGE,
|
|
159
|
+
description: 'Include additional context in the conversation.'
|
|
160
|
+
};
|
|
157
161
|
|
|
158
|
-
export { MOCK_RESPONSE_MESSAGE, MOCK_RESPONSE_MESSAGE_FOR_STREAMING, MOCK_USER_PROMPT_MESSAGE, SLASH_COMMANDS, generateMockResponseChunks, generateSeparateChunks, renderGFM, renderMarkdown };
|
|
162
|
+
export { INCLUDE_SLASH_COMMAND, MOCK_RESPONSE_MESSAGE, MOCK_RESPONSE_MESSAGE_FOR_STREAMING, MOCK_USER_PROMPT_MESSAGE, SLASH_COMMANDS, generateMockResponseChunks, generateSeparateChunks, renderGFM, renderMarkdown };
|
package/dist/index.js
CHANGED
|
@@ -89,6 +89,7 @@ export { default as GlAccordionItem } from './components/base/accordion/accordio
|
|
|
89
89
|
export { default as GlExperimentBadge } from './components/experimental/experiment_badge/experiment_badge';
|
|
90
90
|
export { default as GlDuoUserFeedback } from './components/experimental/duo/user_feedback/user_feedback';
|
|
91
91
|
export { default as GlDuoChat } from './components/experimental/duo/chat/duo_chat';
|
|
92
|
+
export { default as GlDuoChatContextItemMenu } from './components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu';
|
|
92
93
|
export { default as GlAnimatedNumber } from './components/utilities/animated_number/animated_number';
|
|
93
94
|
export { default as GlFriendlyWrap } from './components/utilities/friendly_wrap/friendly_wrap';
|
|
94
95
|
export { default as GlIntersperse } from './components/utilities/intersperse/intersperse';
|
package/package.json
CHANGED
|
@@ -88,6 +88,7 @@ export default {
|
|
|
88
88
|
<button
|
|
89
89
|
class="gl-flex gl-w-full gl-items-center gl-border-0 gl-bg-transparent gl-p-0 gl-text-left gl-text-xs gl-lowercase gl-text-gray-500"
|
|
90
90
|
data-testid="chat-context-selections-title"
|
|
91
|
+
type="button"
|
|
91
92
|
@click="toggleCollapse"
|
|
92
93
|
>
|
|
93
94
|
<gl-icon :name="collapseIconName" data-testid="chat-context-collapse-icon" /> {{ title }}
|
|
@@ -15,7 +15,13 @@ import { SafeHtmlDirective as SafeHtml } from '../../../../directives/safe_html/
|
|
|
15
15
|
import GlDuoChatLoader from './components/duo_chat_loader/duo_chat_loader.vue';
|
|
16
16
|
import GlDuoChatPredefinedPrompts from './components/duo_chat_predefined_prompts/duo_chat_predefined_prompts.vue';
|
|
17
17
|
import GlDuoChatConversation from './components/duo_chat_conversation/duo_chat_conversation.vue';
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
CHAT_CLEAN_MESSAGE,
|
|
20
|
+
CHAT_RESET_MESSAGE,
|
|
21
|
+
CHAT_CLEAR_MESSAGE,
|
|
22
|
+
CHAT_INCLUDE_MESSAGE,
|
|
23
|
+
} from './constants';
|
|
24
|
+
import { INCLUDE_SLASH_COMMAND } from './mock_data';
|
|
19
25
|
|
|
20
26
|
export const i18n = {
|
|
21
27
|
CHAT_DEFAULT_TITLE: 'GitLab Duo Chat',
|
|
@@ -214,6 +220,8 @@ export default {
|
|
|
214
220
|
activeCommandIndex: 0,
|
|
215
221
|
displaySubmitButton: true,
|
|
216
222
|
compositionJustEnded: false,
|
|
223
|
+
contextItemsMenuIsOpen: false,
|
|
224
|
+
contextItemMenuRef: null,
|
|
217
225
|
};
|
|
218
226
|
},
|
|
219
227
|
computed: {
|
|
@@ -241,6 +249,9 @@ export default {
|
|
|
241
249
|
lastMessage() {
|
|
242
250
|
return this.messages?.[this.messages.length - 1];
|
|
243
251
|
},
|
|
252
|
+
caseInsensitivePrompt() {
|
|
253
|
+
return this.prompt.toLowerCase().trim();
|
|
254
|
+
},
|
|
244
255
|
resetDisabled() {
|
|
245
256
|
if (this.isLoading || !this.hasMessages) {
|
|
246
257
|
return true;
|
|
@@ -257,20 +268,36 @@ export default {
|
|
|
257
268
|
);
|
|
258
269
|
},
|
|
259
270
|
filteredSlashCommands() {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
271
|
+
return this.slashCommands
|
|
272
|
+
.filter((c) => c.name.toLowerCase().startsWith(this.caseInsensitivePrompt))
|
|
273
|
+
.filter((c) => {
|
|
274
|
+
if (c.name === CHAT_INCLUDE_MESSAGE) {
|
|
275
|
+
return this.hasContextItemSelectionMenu;
|
|
276
|
+
}
|
|
277
|
+
return true;
|
|
278
|
+
});
|
|
264
279
|
},
|
|
265
280
|
shouldShowSlashCommands() {
|
|
266
|
-
if (!this.withSlashCommands) return false;
|
|
267
|
-
const
|
|
268
|
-
const startsWithSlash = caseInsensitivePrompt.startsWith('/');
|
|
281
|
+
if (!this.withSlashCommands || this.contextItemsMenuIsOpen) return false;
|
|
282
|
+
const startsWithSlash = this.caseInsensitivePrompt.startsWith('/');
|
|
269
283
|
const startsWithSlashCommand = this.slashCommands.some((c) =>
|
|
270
|
-
caseInsensitivePrompt.startsWith(c.name)
|
|
284
|
+
this.caseInsensitivePrompt.startsWith(c.name)
|
|
271
285
|
);
|
|
272
286
|
return startsWithSlash && this.filteredSlashCommands.length && !startsWithSlashCommand;
|
|
273
287
|
},
|
|
288
|
+
shouldShowContextItemSelectionMenu() {
|
|
289
|
+
if (!this.hasContextItemSelectionMenu) {
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const isSlash = this.caseInsensitivePrompt === '/';
|
|
294
|
+
if (!this.caseInsensitivePrompt || isSlash) {
|
|
295
|
+
// 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
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return INCLUDE_SLASH_COMMAND.name.startsWith(this.caseInsensitivePrompt);
|
|
300
|
+
},
|
|
274
301
|
inputPlaceholder() {
|
|
275
302
|
if (this.chatPromptPlaceholder) {
|
|
276
303
|
return this.chatPromptPlaceholder;
|
|
@@ -280,6 +307,9 @@ export default {
|
|
|
280
307
|
? i18n.CHAT_PROMPT_PLACEHOLDER_WITH_COMMANDS
|
|
281
308
|
: i18n.CHAT_PROMPT_PLACEHOLDER_DEFAULT;
|
|
282
309
|
},
|
|
310
|
+
hasContextItemSelectionMenu() {
|
|
311
|
+
return Boolean(this.contextItemMenuRef);
|
|
312
|
+
},
|
|
283
313
|
},
|
|
284
314
|
watch: {
|
|
285
315
|
isLoading(newVal) {
|
|
@@ -322,28 +352,42 @@ export default {
|
|
|
322
352
|
this.setPromptAndFocus();
|
|
323
353
|
},
|
|
324
354
|
sendChatPrompt() {
|
|
325
|
-
if (!this.displaySubmitButton) {
|
|
355
|
+
if (!this.displaySubmitButton || this.contextItemsMenuIsOpen) {
|
|
326
356
|
return;
|
|
327
357
|
}
|
|
328
358
|
if (this.prompt) {
|
|
329
|
-
if (this.
|
|
359
|
+
if (this.caseInsensitivePrompt === CHAT_RESET_MESSAGE && this.resetDisabled) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (
|
|
364
|
+
this.caseInsensitivePrompt.startsWith(CHAT_INCLUDE_MESSAGE) &&
|
|
365
|
+
this.hasContextItemSelectionMenu
|
|
366
|
+
) {
|
|
367
|
+
this.contextItemsMenuIsOpen = true;
|
|
330
368
|
return;
|
|
331
369
|
}
|
|
370
|
+
|
|
371
|
+
if (
|
|
372
|
+
![CHAT_RESET_MESSAGE, CHAT_CLEAN_MESSAGE, CHAT_CLEAR_MESSAGE].includes(
|
|
373
|
+
this.caseInsensitivePrompt
|
|
374
|
+
)
|
|
375
|
+
) {
|
|
376
|
+
this.displaySubmitButton = false;
|
|
377
|
+
}
|
|
378
|
+
|
|
332
379
|
/**
|
|
333
380
|
* Emitted when a new user prompt should be sent out.
|
|
334
381
|
*
|
|
335
382
|
* @param {String} prompt The user prompt to send.
|
|
336
383
|
*/
|
|
337
|
-
|
|
338
|
-
if (![CHAT_RESET_MESSAGE, CHAT_CLEAN_MESSAGE, CHAT_CLEAR_MESSAGE].includes(this.prompt)) {
|
|
339
|
-
this.displaySubmitButton = false;
|
|
340
|
-
}
|
|
341
384
|
this.$emit('send-chat-prompt', this.prompt.trim());
|
|
342
385
|
|
|
343
386
|
this.setPromptAndFocus();
|
|
344
387
|
}
|
|
345
388
|
},
|
|
346
389
|
sendPredefinedPrompt(prompt) {
|
|
390
|
+
this.contextItemsMenuIsOpen = false;
|
|
347
391
|
this.prompt = prompt;
|
|
348
392
|
this.sendChatPrompt();
|
|
349
393
|
},
|
|
@@ -379,6 +423,18 @@ export default {
|
|
|
379
423
|
onInputKeyup(e) {
|
|
380
424
|
const { key } = e;
|
|
381
425
|
|
|
426
|
+
if (this.contextItemsMenuIsOpen) {
|
|
427
|
+
if (!this.shouldShowContextItemSelectionMenu) {
|
|
428
|
+
this.contextItemsMenuIsOpen = false;
|
|
429
|
+
}
|
|
430
|
+
this.contextItemMenuRef?.handleKeyUp(e);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
if (this.caseInsensitivePrompt === INCLUDE_SLASH_COMMAND.name) {
|
|
434
|
+
this.contextItemsMenuIsOpen = true;
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
|
|
382
438
|
if (this.shouldShowSlashCommands) {
|
|
383
439
|
e.preventDefault();
|
|
384
440
|
|
|
@@ -426,6 +482,10 @@ export default {
|
|
|
426
482
|
this.sendChatPrompt();
|
|
427
483
|
} else {
|
|
428
484
|
this.setPromptAndFocus(`${command.name} `);
|
|
485
|
+
|
|
486
|
+
if (command.name === CHAT_INCLUDE_MESSAGE && this.hasContextItemSelectionMenu) {
|
|
487
|
+
this.contextItemsMenuIsOpen = true;
|
|
488
|
+
}
|
|
429
489
|
}
|
|
430
490
|
},
|
|
431
491
|
onInsertCodeSnippet(e) {
|
|
@@ -435,6 +495,13 @@ export default {
|
|
|
435
495
|
*/
|
|
436
496
|
this.$emit('insert-code-snippet', e);
|
|
437
497
|
},
|
|
498
|
+
closeContextItemsMenuOpen() {
|
|
499
|
+
this.contextItemsMenuIsOpen = false;
|
|
500
|
+
this.setPromptAndFocus();
|
|
501
|
+
},
|
|
502
|
+
setContextItemsMenuRef(ref) {
|
|
503
|
+
this.contextItemMenuRef = ref;
|
|
504
|
+
},
|
|
438
505
|
},
|
|
439
506
|
i18n,
|
|
440
507
|
emptySvg,
|
|
@@ -561,6 +628,19 @@ export default {
|
|
|
561
628
|
:class="{ 'duo-chat-drawer-body-scrim-on-footer': !scrolledToBottom }"
|
|
562
629
|
>
|
|
563
630
|
<gl-form data-testid="chat-prompt-form" @submit.stop.prevent="sendChatPrompt">
|
|
631
|
+
<div class="gl-relative gl-max-w-full">
|
|
632
|
+
<!--
|
|
633
|
+
@slot For integrating `<gl-context-items-menu>` component if pinned-context should be available. The following scopedSlot properties are provided: `isOpen`, `onClose`, `setRef`, `focusPrompt`, which should be passed to the `<gl-context-items-menu>` component when rendering, e.g. `<template #context-items-menu="{ isOpen, onClose, setRef, focusPrompt }">` `<gl-duo-chat-context-item-menu :ref="setRef" :open="isOpen" @close="onClose" @focus-prompt="focusPrompt" ...`
|
|
634
|
+
-->
|
|
635
|
+
<slot
|
|
636
|
+
name="context-items-menu"
|
|
637
|
+
:is-open="contextItemsMenuIsOpen"
|
|
638
|
+
:on-close="closeContextItemsMenuOpen"
|
|
639
|
+
:set-ref="setContextItemsMenuRef"
|
|
640
|
+
:focus-prompt="focusChatInput"
|
|
641
|
+
></slot>
|
|
642
|
+
</div>
|
|
643
|
+
|
|
564
644
|
<gl-form-input-group>
|
|
565
645
|
<div
|
|
566
646
|
class="duo-chat-input gl-min-h-8 gl-max-w-full gl-grow gl-rounded-base gl-bg-white gl-align-top gl-shadow-inner-1-gray-400"
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
MESSAGE_MODEL_ROLES,
|
|
5
5
|
CHAT_RESET_MESSAGE,
|
|
6
6
|
CHAT_CLEAN_MESSAGE,
|
|
7
|
+
CHAT_INCLUDE_MESSAGE,
|
|
7
8
|
} from './constants';
|
|
8
9
|
import { getMockContextItems } from './components/duo_chat_context/mock_context_data';
|
|
9
10
|
|
|
@@ -170,3 +171,8 @@ export const SLASH_COMMANDS = [
|
|
|
170
171
|
description: 'Explain the selected snippet.',
|
|
171
172
|
},
|
|
172
173
|
];
|
|
174
|
+
|
|
175
|
+
export const INCLUDE_SLASH_COMMAND = {
|
|
176
|
+
name: CHAT_INCLUDE_MESSAGE,
|
|
177
|
+
description: 'Include additional context in the conversation.',
|
|
178
|
+
};
|
package/src/index.js
CHANGED
|
@@ -100,6 +100,7 @@ export { default as GlAccordionItem } from './components/base/accordion/accordio
|
|
|
100
100
|
export { default as GlExperimentBadge } from './components/experimental/experiment_badge/experiment_badge.vue';
|
|
101
101
|
export { default as GlDuoUserFeedback } from './components/experimental/duo/user_feedback/user_feedback.vue';
|
|
102
102
|
export { default as GlDuoChat } from './components/experimental/duo/chat/duo_chat.vue';
|
|
103
|
+
export { default as GlDuoChatContextItemMenu } from './components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_menu/duo_chat_context_item_menu.vue';
|
|
103
104
|
|
|
104
105
|
// Utilities
|
|
105
106
|
export { default as GlAnimatedNumber } from './components/utilities/animated_number/animated_number.vue';
|