@gitlab/duo-ui 8.22.0 → 8.23.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 +14 -0
- package/dist/components/chat/components/duo_chat_message/duo_chat_message.js +6 -24
- package/dist/components/chat/components/duo_chat_message/message_feedback.js +90 -0
- package/dist/components/chat/components/duo_chat_message/message_types/message_agent.js +9 -2
- package/dist/components/chat/components/duo_chat_threads/duo_chat_threads.js +5 -4
- package/dist/components/chat/constants.js +1 -0
- package/dist/components/chat/mock_data.js +6 -1
- package/package.json +5 -5
- package/src/components/chat/components/duo_chat_message/duo_chat_message.vue +9 -54
- package/src/components/chat/components/duo_chat_message/message_feedback.vue +83 -0
- package/src/components/chat/components/duo_chat_message/message_types/message_agent.vue +10 -1
- package/src/components/chat/components/duo_chat_threads/duo_chat_threads.vue +5 -12
- package/src/components/chat/constants.js +1 -0
- package/src/components/chat/mock_data.js +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [8.23.0](https://gitlab.com/gitlab-org/duo-ui/compare/v8.22.1...v8.23.0) (2025-06-26)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* add message feedback to agentic messages ([04ca354](https://gitlab.com/gitlab-org/duo-ui/commit/04ca354f2a7e1e54074222f2672dd3967737452e))
|
|
7
|
+
|
|
8
|
+
## [8.22.1](https://gitlab.com/gitlab-org/duo-ui/compare/v8.22.0...v8.22.1) (2025-06-20)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **chat:** Fix chat history group dates ([548c507](https://gitlab.com/gitlab-org/duo-ui/commit/548c5078090d0a648824727a59a0fe6f727d31f2))
|
|
14
|
+
|
|
1
15
|
# [8.22.0](https://gitlab.com/gitlab-org/duo-ui/compare/v8.21.0...v8.22.0) (2025-06-18)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -2,10 +2,10 @@ import { GlFormGroup, GlFormTextarea, GlIcon, GlAnimatedLoaderIcon, GlButton, Gl
|
|
|
2
2
|
import { translate, translatePlural, sprintf } from '@gitlab/ui/dist/utils/i18n';
|
|
3
3
|
import throttle from 'lodash/throttle';
|
|
4
4
|
import DuoChatContextItemSelections from '../duo_chat_context/duo_chat_context_item_selections/duo_chat_context_item_selections';
|
|
5
|
-
import GlDuoUserFeedback from '../../../user_feedback/user_feedback';
|
|
6
5
|
import { SELECTED_CONTEXT_ITEMS_DEFAULT_COLLAPSED, MESSAGE_MODEL_ROLES } from '../../constants';
|
|
7
6
|
import DocumentationSources from '../duo_chat_message_sources/duo_chat_message_sources';
|
|
8
7
|
import { renderDuoChatMarkdownPreview } from '../../markdown_renderer';
|
|
8
|
+
import MessageFeedback from './message_feedback';
|
|
9
9
|
import { CopyCodeElement } from './copy_code_element';
|
|
10
10
|
import { InsertCodeSnippetElement } from './insert_code_snippet_element';
|
|
11
11
|
import { concatUntilEmpty, checkClipboardPermissions } from './utils';
|
|
@@ -19,18 +19,10 @@ import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
|
|
|
19
19
|
const COMPONENT_FOR_MESSAGE_TYPE = {
|
|
20
20
|
tool: () => ToolMessage,
|
|
21
21
|
request: () => InputRequestedMessage,
|
|
22
|
-
workflow_end: () => WorkflowEndMessage
|
|
22
|
+
workflow_end: () => WorkflowEndMessage,
|
|
23
|
+
agent: () => AgentMessage
|
|
23
24
|
};
|
|
24
25
|
const i18n = {
|
|
25
|
-
MODAL: {
|
|
26
|
-
TITLE: translate('DuoChatMessage.modalTitle', 'Give feedback on GitLab Duo Chat'),
|
|
27
|
-
ALERT_TEXT: translate('DuoChatMessage.modalAlertText', 'GitLab team members cannot view your conversation. Please be as descriptive as possible.'),
|
|
28
|
-
DID_WHAT: translate('DuoChatMessage.modalDidWhat', 'What were you doing?'),
|
|
29
|
-
INTERACTION: translate('DuoChatMessage.modalInteraction', 'The situation in which you interacted with GitLab Duo Chat.'),
|
|
30
|
-
IMPROVE_WHAT: translate('DuoChatMessage.modalImproveWhat', 'How could the response be improved?'),
|
|
31
|
-
BETTER_RESPONSE: translate('DuoChatMessage.modalBetterResponse', 'How the response might better meet your needs.'),
|
|
32
|
-
MESSAGE_ERROR: translate('DuoChatMessage.modalMessageError', 'Error sending the message')
|
|
33
|
-
},
|
|
34
26
|
CHAT_MESSAGE_COPIED: translate('DuoChatMessage.chatMessageCopied', 'Copied'),
|
|
35
27
|
CHAT_MESSAGE_COPY: translate('DuoChatMessage.chatMessageCopyToClipboard', 'Copy to clipboard'),
|
|
36
28
|
FROM_ME: translate('DuoChatMessage.fromMe', 'Me:'),
|
|
@@ -45,7 +37,7 @@ var script = {
|
|
|
45
37
|
components: {
|
|
46
38
|
DocumentationSources,
|
|
47
39
|
DuoChatContextItemSelections,
|
|
48
|
-
|
|
40
|
+
MessageFeedback,
|
|
49
41
|
GlFormGroup,
|
|
50
42
|
GlFormTextarea,
|
|
51
43
|
GlIcon,
|
|
@@ -56,12 +48,6 @@ var script = {
|
|
|
56
48
|
SafeHtml: GlSafeHtmlDirective,
|
|
57
49
|
GlTooltip: GlTooltipDirective
|
|
58
50
|
},
|
|
59
|
-
provide() {
|
|
60
|
-
return {
|
|
61
|
-
modalTitle: i18n.MODAL.TITLE,
|
|
62
|
-
modalAlertText: i18n.MODAL.ALERT_TEXT
|
|
63
|
-
};
|
|
64
|
-
},
|
|
65
51
|
inject: {
|
|
66
52
|
// Note, we likely might move away from Provide/Inject for this
|
|
67
53
|
// and only ship the versions that are currently in the default
|
|
@@ -109,8 +95,6 @@ var script = {
|
|
|
109
95
|
},
|
|
110
96
|
data() {
|
|
111
97
|
return {
|
|
112
|
-
didWhat: '',
|
|
113
|
-
improveWhat: '',
|
|
114
98
|
messageWatcher: null,
|
|
115
99
|
// imperatively set up watcher on message
|
|
116
100
|
messageChunks: [],
|
|
@@ -141,7 +125,7 @@ var script = {
|
|
|
141
125
|
},
|
|
142
126
|
hasFeedback() {
|
|
143
127
|
var _this$message$extras2;
|
|
144
|
-
return (_this$message$extras2 = this.message.extras) === null || _this$message$extras2 === void 0 ? void 0 : _this$message$extras2.hasFeedback;
|
|
128
|
+
return Boolean((_this$message$extras2 = this.message.extras) === null || _this$message$extras2 === void 0 ? void 0 : _this$message$extras2.hasFeedback);
|
|
145
129
|
},
|
|
146
130
|
defaultContent() {
|
|
147
131
|
if (this.message.contentHtml) {
|
|
@@ -246,8 +230,6 @@ var script = {
|
|
|
246
230
|
logEvent(e) {
|
|
247
231
|
this.$emit('track-feedback', {
|
|
248
232
|
...e,
|
|
249
|
-
didWhat: this.didWhat,
|
|
250
|
-
improveWhat: this.improveWhat,
|
|
251
233
|
message: this.message
|
|
252
234
|
});
|
|
253
235
|
},
|
|
@@ -323,7 +305,7 @@ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=
|
|
|
323
305
|
'gl-bg-subtle': _vm.isAssistantMessage && !_vm.error,
|
|
324
306
|
'duo-chat-message-with-error gl-bg-feedback-danger': _vm.error,
|
|
325
307
|
'!gl-rounded-br-none': _vm.shouldShowCopyAction,
|
|
326
|
-
},on:{"insert-code-snippet":_vm.onInsertCodeSnippet,"copy-code-snippet":_vm.onCopyCodeSnippet}},[(_vm.showA11yFromText)?_c('div',{staticClass:"gl-sr-only"},[_vm._v("\n "+_vm._s(_vm.isUserMessage ? _vm.$options.i18n.FROM_ME : _vm.$options.i18n.FROM_DUO)+"\n ")]):_vm._e(),_vm._v(" "),(_vm.error)?_c('gl-icon',{staticClass:"error-icon gl-mr-3 gl-shrink-0 gl-text-danger",attrs:{"aria-label":_vm.$options.i18n.MESSAGE_ERROR,"name":"error","size":16,"data-testid":"error"}}):_vm._e(),_vm._v(" "),_c('div',{ref:"content-wrapper",class:{ 'has-error': _vm.error }},[(_vm.displaySelectedContextItems && _vm.isAssistantMessage)?_c('duo-chat-context-item-selections',{attrs:{"selections":_vm.selectedContextItems,"title":_vm.selectedContextItemsTitle,"default-collapsed":_vm.selectedContextItemsDefaultCollapsed,"variant":"assistant"},on:{"get-content":_vm.onGetContextItemContent}}):_vm._e(),_vm._v(" "),(_vm.error)?_c('div',{directives:[{name:"safe-html",rawName:"v-safe-html:[$options.safeHtmlConfigExtension]",value:(_vm.renderedError),expression:"renderedError",arg:_vm.$options.safeHtmlConfigExtension}],ref:"error-message"}):_c('div',[_c('div',{directives:[{name:"safe-html",rawName:"v-safe-html:[$options.safeHtmlConfigExtension]",value:(_vm.messageContent),expression:"messageContent",arg:_vm.$options.safeHtmlConfigExtension}],ref:"content"}),_vm._v(" "),(_vm.isAssistantMessage)?[(_vm.sources)?_c('documentation-sources',{attrs:{"sources":_vm.sources}}):_vm._e(),_vm._v(" "),_c('div',{staticClass:"duo-chat-message-feedback gl-mt-4 gl-flex gl-items-end"},[(_vm.isChunkAndNotCancelled)?_c('gl-animated-loader-icon',{attrs:{"is-on":true}}):_vm._e(),_vm._v(" "),(_vm.shouldShowFeedbackLink)?_c('
|
|
308
|
+
},on:{"insert-code-snippet":_vm.onInsertCodeSnippet,"copy-code-snippet":_vm.onCopyCodeSnippet}},[(_vm.showA11yFromText)?_c('div',{staticClass:"gl-sr-only"},[_vm._v("\n "+_vm._s(_vm.isUserMessage ? _vm.$options.i18n.FROM_ME : _vm.$options.i18n.FROM_DUO)+"\n ")]):_vm._e(),_vm._v(" "),(_vm.error)?_c('gl-icon',{staticClass:"error-icon gl-mr-3 gl-shrink-0 gl-text-danger",attrs:{"aria-label":_vm.$options.i18n.MESSAGE_ERROR,"name":"error","size":16,"data-testid":"error"}}):_vm._e(),_vm._v(" "),_c('div',{ref:"content-wrapper",class:{ 'has-error': _vm.error }},[(_vm.displaySelectedContextItems && _vm.isAssistantMessage)?_c('duo-chat-context-item-selections',{attrs:{"selections":_vm.selectedContextItems,"title":_vm.selectedContextItemsTitle,"default-collapsed":_vm.selectedContextItemsDefaultCollapsed,"variant":"assistant"},on:{"get-content":_vm.onGetContextItemContent}}):_vm._e(),_vm._v(" "),(_vm.error)?_c('div',{directives:[{name:"safe-html",rawName:"v-safe-html:[$options.safeHtmlConfigExtension]",value:(_vm.renderedError),expression:"renderedError",arg:_vm.$options.safeHtmlConfigExtension}],ref:"error-message"}):_c('div',[_c('div',{directives:[{name:"safe-html",rawName:"v-safe-html:[$options.safeHtmlConfigExtension]",value:(_vm.messageContent),expression:"messageContent",arg:_vm.$options.safeHtmlConfigExtension}],ref:"content"}),_vm._v(" "),(_vm.isAssistantMessage)?[(_vm.sources)?_c('documentation-sources',{attrs:{"sources":_vm.sources}}):_vm._e(),_vm._v(" "),_c('div',{staticClass:"duo-chat-message-feedback gl-mt-4 gl-flex gl-items-end"},[(_vm.isChunkAndNotCancelled)?_c('gl-animated-loader-icon',{attrs:{"is-on":true}}):_vm._e(),_vm._v(" "),(_vm.shouldShowFeedbackLink)?_c('message-feedback',{attrs:{"has-feedback":_vm.hasFeedback},on:{"feedback":_vm.logEvent}}):_vm._e()],1)]:_vm._e()],2),_vm._v(" "),(_vm.displaySelectedContextItems && _vm.isUserMessage)?_c('duo-chat-context-item-selections',{attrs:{"selections":_vm.selectedContextItems,"title":_vm.selectedContextItemsTitle,"default-collapsed":_vm.selectedContextItemsDefaultCollapsed,"variant":"user"},on:{"get-content":_vm.onGetContextItemContent}}):_vm._e()],1)],1),_vm._v(" "),_c('transition',{attrs:{"name":"duo-chat-message-actions"}},[(_vm.shouldShowCopyAction)?_c('div',{staticClass:"gl-bg-subtle duo-chat-message-actions gl-rounded-tr-lg gl-rounded-br-lg"},[_c('gl-button',{directives:[{name:"gl-tooltip",rawName:"v-gl-tooltip.hover",modifiers:{"hover":true}}],class:{ '!gl-text-success': _vm.copied },attrs:{"title":_vm.copied ? _vm.$options.i18n.CHAT_MESSAGE_COPIED : _vm.$options.i18n.CHAT_MESSAGE_COPY,"icon":_vm.copied ? 'check-circle-filled' : 'copy-to-clipboard',"category":"tertiary"},on:{"click":_vm.copyMessage}})],1):_vm._e()])]:_c(_vm.componentForMessageType(_vm.message),{tag:"component",attrs:{"message":_vm.message,"with-feedback":_vm.withFeedback,"data-testid":"workflow-message"},on:{"open-file-path":_vm.onOpenFilePath,"feedback":_vm.logEvent}})],2)};
|
|
327
309
|
var __vue_staticRenderFns__ = [];
|
|
328
310
|
|
|
329
311
|
/* style */
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { GlFormGroup, GlFormTextarea } from '@gitlab/ui';
|
|
2
|
+
import { translate } from '@gitlab/ui/dist/utils/i18n';
|
|
3
|
+
import GlDuoUserFeedback from '../../../user_feedback/user_feedback';
|
|
4
|
+
import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
|
|
5
|
+
|
|
6
|
+
const i18n = {
|
|
7
|
+
TITLE: translate('DuoChatMessage.modalTitle', 'Give feedback on GitLab Duo Chat'),
|
|
8
|
+
ALERT_TEXT: translate('DuoChatMessage.modalAlertText', 'GitLab team members cannot view your conversation. Please be as descriptive as possible.'),
|
|
9
|
+
DID_WHAT: translate('DuoChatMessage.modalDidWhat', 'What were you doing?'),
|
|
10
|
+
INTERACTION: translate('DuoChatMessage.modalInteraction', 'The situation in which you interacted with GitLab Duo Chat.'),
|
|
11
|
+
IMPROVE_WHAT: translate('DuoChatMessage.modalImproveWhat', 'How could the response be improved?'),
|
|
12
|
+
BETTER_RESPONSE: translate('DuoChatMessage.modalBetterResponse', 'How the response might better meet your needs.'),
|
|
13
|
+
MESSAGE_ERROR: translate('DuoChatMessage.modalMessageError', 'Error sending the message')
|
|
14
|
+
};
|
|
15
|
+
var script = {
|
|
16
|
+
i18n,
|
|
17
|
+
name: 'MessageFeedback',
|
|
18
|
+
components: {
|
|
19
|
+
GlDuoUserFeedback,
|
|
20
|
+
GlFormGroup,
|
|
21
|
+
GlFormTextarea
|
|
22
|
+
},
|
|
23
|
+
provide() {
|
|
24
|
+
return {
|
|
25
|
+
modalTitle: i18n.TITLE,
|
|
26
|
+
modalAlertText: i18n.ALERT_TEXT
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
props: {
|
|
30
|
+
hasFeedback: {
|
|
31
|
+
required: false,
|
|
32
|
+
default: false,
|
|
33
|
+
type: Boolean
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
data() {
|
|
37
|
+
return {
|
|
38
|
+
didWhat: '',
|
|
39
|
+
improveWhat: ''
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
methods: {
|
|
43
|
+
logEvent(e) {
|
|
44
|
+
this.$emit('feedback', {
|
|
45
|
+
...e,
|
|
46
|
+
didWhat: this.didWhat,
|
|
47
|
+
improveWhat: this.improveWhat
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/* script */
|
|
54
|
+
const __vue_script__ = script;
|
|
55
|
+
|
|
56
|
+
/* template */
|
|
57
|
+
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-duo-user-feedback',{attrs:{"feedback-received":_vm.hasFeedback,"modal-title":_vm.$options.i18n.TITLE,"modal-alert":_vm.$options.i18n.ALERT_TEXT},on:{"feedback":_vm.logEvent},scopedSlots:_vm._u([{key:"feedback-extra-fields",fn:function(){return [_c('gl-form-group',{attrs:{"label":_vm.$options.i18n.DID_WHAT,"optional":"","data-testid":"did-what-form-group"}},[_c('gl-form-textarea',{attrs:{"placeholder":_vm.$options.i18n.INTERACTION},model:{value:(_vm.didWhat),callback:function ($$v) {_vm.didWhat=$$v;},expression:"didWhat"}})],1),_vm._v(" "),_c('gl-form-group',{attrs:{"label":_vm.$options.i18n.IMPROVE_WHAT,"optional":"","data-testid":"improve-what-form-group"}},[_c('gl-form-textarea',{attrs:{"placeholder":_vm.$options.i18n.BETTER_RESPONSE},model:{value:(_vm.improveWhat),callback:function ($$v) {_vm.improveWhat=$$v;},expression:"improveWhat"}})],1)]},proxy:true}])})};
|
|
58
|
+
var __vue_staticRenderFns__ = [];
|
|
59
|
+
|
|
60
|
+
/* style */
|
|
61
|
+
const __vue_inject_styles__ = undefined;
|
|
62
|
+
/* scoped */
|
|
63
|
+
const __vue_scope_id__ = undefined;
|
|
64
|
+
/* module identifier */
|
|
65
|
+
const __vue_module_identifier__ = undefined;
|
|
66
|
+
/* functional template */
|
|
67
|
+
const __vue_is_functional_template__ = false;
|
|
68
|
+
/* style inject */
|
|
69
|
+
|
|
70
|
+
/* style inject SSR */
|
|
71
|
+
|
|
72
|
+
/* style inject shadow dom */
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
const __vue_component__ = __vue_normalize__(
|
|
77
|
+
{ render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
|
|
78
|
+
__vue_inject_styles__,
|
|
79
|
+
__vue_script__,
|
|
80
|
+
__vue_scope_id__,
|
|
81
|
+
__vue_is_functional_template__,
|
|
82
|
+
__vue_module_identifier__,
|
|
83
|
+
false,
|
|
84
|
+
undefined,
|
|
85
|
+
undefined,
|
|
86
|
+
undefined
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
export default __vue_component__;
|
|
90
|
+
export { i18n };
|
|
@@ -1,15 +1,22 @@
|
|
|
1
|
+
import MessageFeedback from '../message_feedback';
|
|
1
2
|
import BaseMessage from './message_base';
|
|
2
3
|
import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
|
|
3
4
|
|
|
4
5
|
var script = {
|
|
5
6
|
name: 'DuoAgentMessage',
|
|
6
7
|
components: {
|
|
7
|
-
BaseMessage
|
|
8
|
+
BaseMessage,
|
|
9
|
+
MessageFeedback
|
|
8
10
|
},
|
|
9
11
|
props: {
|
|
10
12
|
message: {
|
|
11
13
|
required: true,
|
|
12
14
|
type: Object
|
|
15
|
+
},
|
|
16
|
+
withFeedback: {
|
|
17
|
+
required: false,
|
|
18
|
+
default: false,
|
|
19
|
+
type: Boolean
|
|
13
20
|
}
|
|
14
21
|
},
|
|
15
22
|
computed: {
|
|
@@ -26,7 +33,7 @@ const __vue_script__ = script;
|
|
|
26
33
|
/* template */
|
|
27
34
|
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('base-message',{staticClass:"gl-rounded-bl-none gl-border-1 gl-border-solid gl-text-gray-900 gl-p-4 gl-border-gray-50",class:{
|
|
28
35
|
'gl-border-red-100': _vm.hasError,
|
|
29
|
-
},attrs:{"message":_vm.message},scopedSlots:_vm._u([{key:"message",fn:function(slotProps){return [_vm._t("message",
|
|
36
|
+
},attrs:{"message":_vm.message},scopedSlots:_vm._u([{key:"message",fn:function(slotProps){return [_vm._t("message",function(){return [_vm._v(_vm._s(slotProps.content))]},null,slotProps),_vm._v(" "),(_vm.withFeedback)?_c('message-feedback',{on:{"feedback":function($event){return _vm.$emit('feedback', $event)}}}):_vm._e()]}}],null,true)})};
|
|
30
37
|
var __vue_staticRenderFns__ = [];
|
|
31
38
|
|
|
32
39
|
/* style */
|
|
@@ -26,9 +26,6 @@ var script = {
|
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
28
|
computed: {
|
|
29
|
-
formattedLocalDate() {
|
|
30
|
-
return date => formatLocalizedDate(date, this.preferredLocale);
|
|
31
|
-
},
|
|
32
29
|
groupedThreads() {
|
|
33
30
|
if (!this.hasThreads) {
|
|
34
31
|
return {};
|
|
@@ -46,6 +43,9 @@ var script = {
|
|
|
46
43
|
}
|
|
47
44
|
},
|
|
48
45
|
methods: {
|
|
46
|
+
formattedLocalDate(date) {
|
|
47
|
+
return formatLocalizedDate(date, this.preferredLocale);
|
|
48
|
+
},
|
|
49
49
|
onNewChat() {
|
|
50
50
|
this.$emit('new-chat');
|
|
51
51
|
},
|
|
@@ -63,7 +63,8 @@ var script = {
|
|
|
63
63
|
return new Date(dateA) - new Date(dateB);
|
|
64
64
|
},
|
|
65
65
|
getDateKey(date) {
|
|
66
|
-
|
|
66
|
+
// add 00:00:00 to the date string to make it at midnight local time
|
|
67
|
+
return `${new Date(date).toISOString().split('T')[0]}T00:00:00`;
|
|
67
68
|
},
|
|
68
69
|
sprintf
|
|
69
70
|
},
|
|
@@ -74,6 +74,11 @@ const MOCK_TOOL_MESSAGE = {
|
|
|
74
74
|
name: 'list_files'
|
|
75
75
|
}
|
|
76
76
|
};
|
|
77
|
+
const MOCK_AGENT_MESSAGE = {
|
|
78
|
+
id: '123',
|
|
79
|
+
content: "Search for 'duo.*chat.*message' in directory",
|
|
80
|
+
message_type: MESSAGE_MODEL_ROLES.agent
|
|
81
|
+
};
|
|
77
82
|
const MOCK_TOOL_MESSAGE_WITH_LINK = {
|
|
78
83
|
id: '123',
|
|
79
84
|
content: "Search for 'duo.*chat.*message' in directory",
|
|
@@ -295,4 +300,4 @@ const THREADLIST = [{
|
|
|
295
300
|
title: 'Before the Configuration Committee'
|
|
296
301
|
}];
|
|
297
302
|
|
|
298
|
-
export { INCLUDE_SLASH_COMMAND, MOCK_REQUEST_MESSAGE, MOCK_RESPONSE_MESSAGE, MOCK_RESPONSE_MESSAGE_FOR_STREAMING, MOCK_TOOL_MESSAGE, MOCK_TOOL_MESSAGE_WITH_LINK, MOCK_USER_PROMPT_MESSAGE, MOCK_WORKFLOW_END_MESSAGE, SLASH_COMMANDS, THREADLIST, generateMockResponseChunks, generateSeparateChunks, renderGFM, renderMarkdown };
|
|
303
|
+
export { INCLUDE_SLASH_COMMAND, MOCK_AGENT_MESSAGE, MOCK_REQUEST_MESSAGE, MOCK_RESPONSE_MESSAGE, MOCK_RESPONSE_MESSAGE_FOR_STREAMING, MOCK_TOOL_MESSAGE, MOCK_TOOL_MESSAGE_WITH_LINK, MOCK_USER_PROMPT_MESSAGE, MOCK_WORKFLOW_END_MESSAGE, SLASH_COMMANDS, THREADLIST, generateMockResponseChunks, generateSeparateChunks, renderGFM, renderMarkdown };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/duo-ui",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.23.0",
|
|
4
4
|
"description": "Duo UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -97,10 +97,10 @@
|
|
|
97
97
|
"@babel/plugin-proposal-optional-chaining": "^7.21.0",
|
|
98
98
|
"@babel/preset-env": "^7.27.2",
|
|
99
99
|
"@babel/preset-react": "^7.27.1",
|
|
100
|
-
"@gitlab/eslint-plugin": "21.
|
|
100
|
+
"@gitlab/eslint-plugin": "21.1.0",
|
|
101
101
|
"@gitlab/fonts": "^1.3.0",
|
|
102
102
|
"@gitlab/stylelint-config": "6.2.2",
|
|
103
|
-
"@gitlab/svgs": "^3.
|
|
103
|
+
"@gitlab/svgs": "^3.136.0",
|
|
104
104
|
"@gitlab/ui": "latest",
|
|
105
105
|
"@jest/test-sequencer": "^29.7.0",
|
|
106
106
|
"@rollup/plugin-commonjs": "^11.1.0",
|
|
@@ -155,8 +155,8 @@
|
|
|
155
155
|
"module-alias": "^2.2.2",
|
|
156
156
|
"npm-run-all": "^4.1.5",
|
|
157
157
|
"pikaday": "^1.8.0",
|
|
158
|
-
"playwright": "^1.53.
|
|
159
|
-
"playwright-core": "^1.53.
|
|
158
|
+
"playwright": "^1.53.1",
|
|
159
|
+
"playwright-core": "^1.53.1",
|
|
160
160
|
"plop": "^2.5.4",
|
|
161
161
|
"postcss": "8.4.28",
|
|
162
162
|
"postcss-loader": "^7.0.2",
|
|
@@ -12,12 +12,12 @@ import {
|
|
|
12
12
|
import { sprintf, translate, translatePlural } from '@gitlab/ui/dist/utils/i18n';
|
|
13
13
|
import throttle from 'lodash/throttle';
|
|
14
14
|
import DuoChatContextItemSelections from '../duo_chat_context/duo_chat_context_item_selections/duo_chat_context_item_selections.vue';
|
|
15
|
-
import GlDuoUserFeedback from '../../../user_feedback/user_feedback.vue';
|
|
16
15
|
import { MESSAGE_MODEL_ROLES, SELECTED_CONTEXT_ITEMS_DEFAULT_COLLAPSED } from '../../constants';
|
|
17
16
|
|
|
18
17
|
import DocumentationSources from '../duo_chat_message_sources/duo_chat_message_sources.vue';
|
|
19
18
|
// eslint-disable-next-line no-restricted-imports
|
|
20
19
|
import { renderDuoChatMarkdownPreview } from '../../markdown_renderer';
|
|
20
|
+
import MessageFeedback from './message_feedback.vue';
|
|
21
21
|
import { CopyCodeElement } from './copy_code_element';
|
|
22
22
|
import { InsertCodeSnippetElement } from './insert_code_snippet_element';
|
|
23
23
|
import { checkClipboardPermissions, concatUntilEmpty } from './utils';
|
|
@@ -35,30 +35,10 @@ const COMPONENT_FOR_MESSAGE_TYPE = {
|
|
|
35
35
|
tool: () => ToolMessage,
|
|
36
36
|
request: () => InputRequestedMessage,
|
|
37
37
|
workflow_end: () => WorkflowEndMessage,
|
|
38
|
+
agent: () => AgentMessage,
|
|
38
39
|
};
|
|
39
40
|
|
|
40
41
|
export const i18n = {
|
|
41
|
-
MODAL: {
|
|
42
|
-
TITLE: translate('DuoChatMessage.modalTitle', 'Give feedback on GitLab Duo Chat'),
|
|
43
|
-
ALERT_TEXT: translate(
|
|
44
|
-
'DuoChatMessage.modalAlertText',
|
|
45
|
-
'GitLab team members cannot view your conversation. Please be as descriptive as possible.'
|
|
46
|
-
),
|
|
47
|
-
DID_WHAT: translate('DuoChatMessage.modalDidWhat', 'What were you doing?'),
|
|
48
|
-
INTERACTION: translate(
|
|
49
|
-
'DuoChatMessage.modalInteraction',
|
|
50
|
-
'The situation in which you interacted with GitLab Duo Chat.'
|
|
51
|
-
),
|
|
52
|
-
IMPROVE_WHAT: translate(
|
|
53
|
-
'DuoChatMessage.modalImproveWhat',
|
|
54
|
-
'How could the response be improved?'
|
|
55
|
-
),
|
|
56
|
-
BETTER_RESPONSE: translate(
|
|
57
|
-
'DuoChatMessage.modalBetterResponse',
|
|
58
|
-
'How the response might better meet your needs.'
|
|
59
|
-
),
|
|
60
|
-
MESSAGE_ERROR: translate('DuoChatMessage.modalMessageError', 'Error sending the message'),
|
|
61
|
-
},
|
|
62
42
|
CHAT_MESSAGE_COPIED: translate('DuoChatMessage.chatMessageCopied', 'Copied'),
|
|
63
43
|
CHAT_MESSAGE_COPY: translate('DuoChatMessage.chatMessageCopyToClipboard', 'Copy to clipboard'),
|
|
64
44
|
FROM_ME: translate('DuoChatMessage.fromMe', 'Me:'),
|
|
@@ -74,7 +54,7 @@ export default {
|
|
|
74
54
|
components: {
|
|
75
55
|
DocumentationSources,
|
|
76
56
|
DuoChatContextItemSelections,
|
|
77
|
-
|
|
57
|
+
MessageFeedback,
|
|
78
58
|
GlFormGroup,
|
|
79
59
|
GlFormTextarea,
|
|
80
60
|
GlIcon,
|
|
@@ -85,12 +65,6 @@ export default {
|
|
|
85
65
|
SafeHtml,
|
|
86
66
|
GlTooltip: GlTooltipDirective,
|
|
87
67
|
},
|
|
88
|
-
provide() {
|
|
89
|
-
return {
|
|
90
|
-
modalTitle: i18n.MODAL.TITLE,
|
|
91
|
-
modalAlertText: i18n.MODAL.ALERT_TEXT,
|
|
92
|
-
};
|
|
93
|
-
},
|
|
94
68
|
inject: {
|
|
95
69
|
// Note, we likely might move away from Provide/Inject for this
|
|
96
70
|
// and only ship the versions that are currently in the default
|
|
@@ -138,8 +112,6 @@ export default {
|
|
|
138
112
|
},
|
|
139
113
|
data() {
|
|
140
114
|
return {
|
|
141
|
-
didWhat: '',
|
|
142
|
-
improveWhat: '',
|
|
143
115
|
messageWatcher: null, // imperatively set up watcher on message
|
|
144
116
|
messageChunks: [],
|
|
145
117
|
selectedContextItemsDefaultCollapsed: SELECTED_CONTEXT_ITEMS_DEFAULT_COLLAPSED,
|
|
@@ -167,7 +139,7 @@ export default {
|
|
|
167
139
|
return this.message.extras?.sources;
|
|
168
140
|
},
|
|
169
141
|
hasFeedback() {
|
|
170
|
-
return this.message.extras?.hasFeedback;
|
|
142
|
+
return Boolean(this.message.extras?.hasFeedback);
|
|
171
143
|
},
|
|
172
144
|
defaultContent() {
|
|
173
145
|
if (this.message.contentHtml) {
|
|
@@ -290,8 +262,6 @@ export default {
|
|
|
290
262
|
logEvent(e) {
|
|
291
263
|
this.$emit('track-feedback', {
|
|
292
264
|
...e,
|
|
293
|
-
didWhat: this.didWhat,
|
|
294
|
-
improveWhat: this.improveWhat,
|
|
295
265
|
message: this.message,
|
|
296
266
|
});
|
|
297
267
|
},
|
|
@@ -418,28 +388,11 @@ export default {
|
|
|
418
388
|
|
|
419
389
|
<div class="duo-chat-message-feedback gl-mt-4 gl-flex gl-items-end">
|
|
420
390
|
<gl-animated-loader-icon v-if="isChunkAndNotCancelled" :is-on="true" />
|
|
421
|
-
<
|
|
391
|
+
<message-feedback
|
|
422
392
|
v-if="shouldShowFeedbackLink"
|
|
423
|
-
:feedback
|
|
424
|
-
:modal-title="$options.i18n.MODAL.TITLE"
|
|
425
|
-
:modal-alert="$options.i18n.MODAL.ALERT_TEXT"
|
|
393
|
+
:has-feedback="hasFeedback"
|
|
426
394
|
@feedback="logEvent"
|
|
427
|
-
|
|
428
|
-
<template #feedback-extra-fields>
|
|
429
|
-
<gl-form-group :label="$options.i18n.MODAL.DID_WHAT" optional>
|
|
430
|
-
<gl-form-textarea
|
|
431
|
-
v-model="didWhat"
|
|
432
|
-
:placeholder="$options.i18n.MODAL.INTERACTION"
|
|
433
|
-
/>
|
|
434
|
-
</gl-form-group>
|
|
435
|
-
<gl-form-group :label="$options.i18n.MODAL.IMPROVE_WHAT" optional>
|
|
436
|
-
<gl-form-textarea
|
|
437
|
-
v-model="improveWhat"
|
|
438
|
-
:placeholder="$options.i18n.MODAL.BETTER_RESPONSE"
|
|
439
|
-
/>
|
|
440
|
-
</gl-form-group>
|
|
441
|
-
</template>
|
|
442
|
-
</gl-duo-user-feedback>
|
|
395
|
+
/>
|
|
443
396
|
</div>
|
|
444
397
|
</template>
|
|
445
398
|
</div>
|
|
@@ -473,8 +426,10 @@ export default {
|
|
|
473
426
|
:is="componentForMessageType(message)"
|
|
474
427
|
v-else
|
|
475
428
|
:message="message"
|
|
429
|
+
:with-feedback="withFeedback"
|
|
476
430
|
data-testid="workflow-message"
|
|
477
431
|
@open-file-path="onOpenFilePath"
|
|
432
|
+
@feedback="logEvent"
|
|
478
433
|
/>
|
|
479
434
|
</div>
|
|
480
435
|
</template>
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { GlFormGroup, GlFormTextarea } from '@gitlab/ui';
|
|
3
|
+
import { translate } from '@gitlab/ui/dist/utils/i18n';
|
|
4
|
+
import GlDuoUserFeedback from '../../../user_feedback/user_feedback.vue';
|
|
5
|
+
|
|
6
|
+
export const i18n = {
|
|
7
|
+
TITLE: translate('DuoChatMessage.modalTitle', 'Give feedback on GitLab Duo Chat'),
|
|
8
|
+
ALERT_TEXT: translate(
|
|
9
|
+
'DuoChatMessage.modalAlertText',
|
|
10
|
+
'GitLab team members cannot view your conversation. Please be as descriptive as possible.'
|
|
11
|
+
),
|
|
12
|
+
DID_WHAT: translate('DuoChatMessage.modalDidWhat', 'What were you doing?'),
|
|
13
|
+
INTERACTION: translate(
|
|
14
|
+
'DuoChatMessage.modalInteraction',
|
|
15
|
+
'The situation in which you interacted with GitLab Duo Chat.'
|
|
16
|
+
),
|
|
17
|
+
IMPROVE_WHAT: translate('DuoChatMessage.modalImproveWhat', 'How could the response be improved?'),
|
|
18
|
+
BETTER_RESPONSE: translate(
|
|
19
|
+
'DuoChatMessage.modalBetterResponse',
|
|
20
|
+
'How the response might better meet your needs.'
|
|
21
|
+
),
|
|
22
|
+
MESSAGE_ERROR: translate('DuoChatMessage.modalMessageError', 'Error sending the message'),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default {
|
|
26
|
+
i18n,
|
|
27
|
+
name: 'MessageFeedback',
|
|
28
|
+
components: {
|
|
29
|
+
GlDuoUserFeedback,
|
|
30
|
+
GlFormGroup,
|
|
31
|
+
GlFormTextarea,
|
|
32
|
+
},
|
|
33
|
+
provide() {
|
|
34
|
+
return {
|
|
35
|
+
modalTitle: i18n.TITLE,
|
|
36
|
+
modalAlertText: i18n.ALERT_TEXT,
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
props: {
|
|
40
|
+
hasFeedback: {
|
|
41
|
+
required: false,
|
|
42
|
+
default: false,
|
|
43
|
+
type: Boolean,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
data() {
|
|
47
|
+
return {
|
|
48
|
+
didWhat: '',
|
|
49
|
+
improveWhat: '',
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
methods: {
|
|
53
|
+
logEvent(e) {
|
|
54
|
+
this.$emit('feedback', {
|
|
55
|
+
...e,
|
|
56
|
+
didWhat: this.didWhat,
|
|
57
|
+
improveWhat: this.improveWhat,
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
</script>
|
|
63
|
+
<template>
|
|
64
|
+
<gl-duo-user-feedback
|
|
65
|
+
:feedback-received="hasFeedback"
|
|
66
|
+
:modal-title="$options.i18n.TITLE"
|
|
67
|
+
:modal-alert="$options.i18n.ALERT_TEXT"
|
|
68
|
+
@feedback="logEvent"
|
|
69
|
+
>
|
|
70
|
+
<template #feedback-extra-fields>
|
|
71
|
+
<gl-form-group :label="$options.i18n.DID_WHAT" optional data-testid="did-what-form-group">
|
|
72
|
+
<gl-form-textarea v-model="didWhat" :placeholder="$options.i18n.INTERACTION" />
|
|
73
|
+
</gl-form-group>
|
|
74
|
+
<gl-form-group
|
|
75
|
+
:label="$options.i18n.IMPROVE_WHAT"
|
|
76
|
+
optional
|
|
77
|
+
data-testid="improve-what-form-group"
|
|
78
|
+
>
|
|
79
|
+
<gl-form-textarea v-model="improveWhat" :placeholder="$options.i18n.BETTER_RESPONSE" />
|
|
80
|
+
</gl-form-group>
|
|
81
|
+
</template>
|
|
82
|
+
</gl-duo-user-feedback>
|
|
83
|
+
</template>
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
<script>
|
|
2
|
+
import MessageFeedback from '../message_feedback.vue';
|
|
2
3
|
import BaseMessage from './message_base.vue';
|
|
3
4
|
|
|
4
5
|
export default {
|
|
5
6
|
name: 'DuoAgentMessage',
|
|
6
7
|
components: {
|
|
7
8
|
BaseMessage,
|
|
9
|
+
MessageFeedback,
|
|
8
10
|
},
|
|
9
11
|
props: {
|
|
10
12
|
message: {
|
|
11
13
|
required: true,
|
|
12
14
|
type: Object,
|
|
13
15
|
},
|
|
16
|
+
withFeedback: {
|
|
17
|
+
required: false,
|
|
18
|
+
default: false,
|
|
19
|
+
type: Boolean,
|
|
20
|
+
},
|
|
14
21
|
},
|
|
15
22
|
computed: {
|
|
16
23
|
hasError() {
|
|
@@ -28,7 +35,9 @@ export default {
|
|
|
28
35
|
}"
|
|
29
36
|
>
|
|
30
37
|
<template #message="slotProps">
|
|
31
|
-
<slot name="message" v-bind="slotProps"> </slot>
|
|
38
|
+
<slot name="message" v-bind="slotProps">{{ slotProps.content }}</slot>
|
|
39
|
+
|
|
40
|
+
<message-feedback v-if="withFeedback" @feedback="$emit('feedback', $event)" />
|
|
32
41
|
</template>
|
|
33
42
|
</base-message>
|
|
34
43
|
</template>
|
|
@@ -33,10 +33,6 @@ export default {
|
|
|
33
33
|
},
|
|
34
34
|
|
|
35
35
|
computed: {
|
|
36
|
-
formattedLocalDate() {
|
|
37
|
-
return (date) => formatLocalizedDate(date, this.preferredLocale);
|
|
38
|
-
},
|
|
39
|
-
|
|
40
36
|
groupedThreads() {
|
|
41
37
|
if (!this.hasThreads) {
|
|
42
38
|
return {};
|
|
@@ -53,38 +49,35 @@ export default {
|
|
|
53
49
|
};
|
|
54
50
|
}, {});
|
|
55
51
|
},
|
|
56
|
-
|
|
57
52
|
hasThreads() {
|
|
58
53
|
return this.threads.length > 0;
|
|
59
54
|
},
|
|
60
55
|
},
|
|
61
56
|
|
|
62
57
|
methods: {
|
|
58
|
+
formattedLocalDate(date) {
|
|
59
|
+
return formatLocalizedDate(date, this.preferredLocale);
|
|
60
|
+
},
|
|
63
61
|
onNewChat() {
|
|
64
62
|
this.$emit('new-chat');
|
|
65
63
|
},
|
|
66
|
-
|
|
67
64
|
onSelectThread(thread) {
|
|
68
65
|
this.$emit('select-thread', thread);
|
|
69
66
|
},
|
|
70
|
-
|
|
71
67
|
onDeleteThread(threadId, event) {
|
|
72
68
|
event.stopPropagation();
|
|
73
69
|
this.$emit('delete-thread', threadId);
|
|
74
70
|
},
|
|
75
|
-
|
|
76
71
|
onClose() {
|
|
77
72
|
this.$emit('close');
|
|
78
73
|
},
|
|
79
|
-
|
|
80
74
|
compareThreadDates(dateA, dateB) {
|
|
81
75
|
return new Date(dateA) - new Date(dateB);
|
|
82
76
|
},
|
|
83
|
-
|
|
84
77
|
getDateKey(date) {
|
|
85
|
-
|
|
78
|
+
// add 00:00:00 to the date string to make it at midnight local time
|
|
79
|
+
return `${new Date(date).toISOString().split('T')[0]}T00:00:00`;
|
|
86
80
|
},
|
|
87
|
-
|
|
88
81
|
sprintf,
|
|
89
82
|
},
|
|
90
83
|
i18n,
|
|
@@ -89,6 +89,12 @@ export const MOCK_TOOL_MESSAGE = {
|
|
|
89
89
|
},
|
|
90
90
|
};
|
|
91
91
|
|
|
92
|
+
export const MOCK_AGENT_MESSAGE = {
|
|
93
|
+
id: '123',
|
|
94
|
+
content: "Search for 'duo.*chat.*message' in directory",
|
|
95
|
+
message_type: MESSAGE_MODEL_ROLES.agent,
|
|
96
|
+
};
|
|
97
|
+
|
|
92
98
|
export const MOCK_TOOL_MESSAGE_WITH_LINK = {
|
|
93
99
|
id: '123',
|
|
94
100
|
content: "Search for 'duo.*chat.*message' in directory",
|