@gitlab/duo-ui 10.23.0 → 10.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/components/agentic_chat/agentic_duo_chat.js +37 -18
- package/dist/components/chat/components/duo_chat_header/duo_chat_header.js +4 -4
- package/dist/components/chat/duo_chat.js +54 -35
- package/dist/components.css +1 -1
- package/dist/components.css.map +1 -1
- package/dist/index.js +0 -2
- package/dist/tailwind.css +1 -1
- package/dist/tailwind.css.map +1 -1
- package/package.json +1 -2
- package/src/components/agentic_chat/agentic_duo_chat.vue +244 -210
- package/src/components/chat/components/duo_chat_header/duo_chat_header.vue +22 -24
- package/src/components/chat/duo_chat.scss +2 -1
- package/src/components/chat/duo_chat.vue +238 -214
- package/src/index.js +0 -2
- package/translations.js +4 -5
- package/dist/components/ui/duo_layout/duo_layout.js +0 -100
- package/dist/components/ui/side_rail/side_rail.js +0 -67
- package/src/components/ui/duo_layout/duo_layout.md +0 -0
- package/src/components/ui/duo_layout/duo_layout.vue +0 -95
- package/src/components/ui/side_rail/side_rail.vue +0 -56
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import throttle from 'lodash/throttle';
|
|
3
|
+
import VueResizable from 'vue-resizable';
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
6
|
GlButton,
|
|
6
7
|
GlDropdownItem,
|
|
7
8
|
GlCard,
|
|
9
|
+
GlAlert,
|
|
10
|
+
GlFormInputGroup,
|
|
8
11
|
GlFormTextarea,
|
|
9
12
|
GlForm,
|
|
13
|
+
GlExperimentBadge,
|
|
10
14
|
GlSafeHtmlDirective as SafeHtml,
|
|
11
15
|
} from '@gitlab/ui';
|
|
12
16
|
|
|
@@ -20,8 +24,6 @@ import {
|
|
|
20
24
|
CHAT_NEW_MESSAGE,
|
|
21
25
|
CHAT_INCLUDE_MESSAGE,
|
|
22
26
|
MESSAGE_MODEL_ROLES,
|
|
23
|
-
MAX_PROMPT_LENGTH,
|
|
24
|
-
PROMPT_LENGTH_WARNING,
|
|
25
27
|
} from './constants';
|
|
26
28
|
import { VIEW_TYPES } from './components/duo_chat_header/constants';
|
|
27
29
|
import DuoChatLoader from './components/duo_chat_loader/duo_chat_loader.vue';
|
|
@@ -43,7 +45,7 @@ export const i18n = {
|
|
|
43
45
|
),
|
|
44
46
|
CHAT_PROMPT_PLACEHOLDER_DEFAULT: translate(
|
|
45
47
|
'DuoChat.chatPromptPlaceholderDefault',
|
|
46
|
-
|
|
48
|
+
'GitLab Duo Chat'
|
|
47
49
|
),
|
|
48
50
|
CHAT_PROMPT_PLACEHOLDER_WITH_COMMANDS: translate(
|
|
49
51
|
'DuoChat.chatPromptPlaceholderWithCommands',
|
|
@@ -51,7 +53,6 @@ export const i18n = {
|
|
|
51
53
|
),
|
|
52
54
|
CHAT_SUBMIT_LABEL: translate('DuoChat.chatSubmitLabel', 'Send chat message.'),
|
|
53
55
|
CHAT_CANCEL_LABEL: translate('DuoChat.chatCancelLabel', 'Cancel'),
|
|
54
|
-
CHAT_MODEL_PLACEHOLDER: translate('DuoChat.chatModelPlaceholder', 'GitLab Duo Chat'),
|
|
55
56
|
CHAT_DEFAULT_PREDEFINED_PROMPTS: [
|
|
56
57
|
translate(
|
|
57
58
|
'DuoChat.chatDefaultPredefinedPromptsChangePassword',
|
|
@@ -98,8 +99,11 @@ export default {
|
|
|
98
99
|
name: 'DuoChat',
|
|
99
100
|
components: {
|
|
100
101
|
GlButton,
|
|
102
|
+
GlAlert,
|
|
103
|
+
GlFormInputGroup,
|
|
101
104
|
GlFormTextarea,
|
|
102
105
|
GlForm,
|
|
106
|
+
GlExperimentBadge,
|
|
103
107
|
DuoChatLoader,
|
|
104
108
|
DuoChatPredefinedPrompts,
|
|
105
109
|
DuoChatConversation,
|
|
@@ -107,11 +111,41 @@ export default {
|
|
|
107
111
|
DuoChatThreads,
|
|
108
112
|
GlCard,
|
|
109
113
|
GlDropdownItem,
|
|
114
|
+
VueResizable,
|
|
110
115
|
},
|
|
111
116
|
directives: {
|
|
112
117
|
SafeHtml,
|
|
113
118
|
},
|
|
114
119
|
props: {
|
|
120
|
+
/**
|
|
121
|
+
* Determines if the component should be resizable. When true, it renders inside
|
|
122
|
+
* a `vue-resizable` wrapper; otherwise, a standard `div` is used.
|
|
123
|
+
*/
|
|
124
|
+
shouldRenderResizable: {
|
|
125
|
+
type: Boolean,
|
|
126
|
+
required: false,
|
|
127
|
+
default: false,
|
|
128
|
+
},
|
|
129
|
+
/**
|
|
130
|
+
* Defines the dimensions of the chat container when resizable.
|
|
131
|
+
* By default, the height is set to match the height of the browser window,
|
|
132
|
+
* and the width is fixed at 400px. The `top` position is left undefined,
|
|
133
|
+
* allowing it to be dynamically adjusted if needed.
|
|
134
|
+
*/
|
|
135
|
+
dimensions: {
|
|
136
|
+
type: Object,
|
|
137
|
+
required: false,
|
|
138
|
+
default: () => ({
|
|
139
|
+
width: undefined,
|
|
140
|
+
height: undefined,
|
|
141
|
+
top: undefined,
|
|
142
|
+
left: undefined,
|
|
143
|
+
maxWidth: undefined,
|
|
144
|
+
minWidth: 400,
|
|
145
|
+
maxHeight: undefined,
|
|
146
|
+
minHeight: 400,
|
|
147
|
+
}),
|
|
148
|
+
},
|
|
115
149
|
/**
|
|
116
150
|
* The title of the chat/feature.
|
|
117
151
|
*/
|
|
@@ -280,14 +314,10 @@ export default {
|
|
|
280
314
|
default: () => ['en-US', 'en'],
|
|
281
315
|
validator: localeValidator,
|
|
282
316
|
},
|
|
283
|
-
shouldRenderResizable: {
|
|
284
|
-
type: Boolean,
|
|
285
|
-
required: false,
|
|
286
|
-
default: false,
|
|
287
|
-
},
|
|
288
317
|
},
|
|
289
318
|
data() {
|
|
290
319
|
return {
|
|
320
|
+
isHidden: false,
|
|
291
321
|
prompt: '',
|
|
292
322
|
scrolledToBottom: true,
|
|
293
323
|
activeCommandIndex: 0,
|
|
@@ -296,9 +326,6 @@ export default {
|
|
|
296
326
|
contextItemsMenuIsOpen: false,
|
|
297
327
|
contextItemMenuRef: null,
|
|
298
328
|
currentView: this.multiThreadedView,
|
|
299
|
-
maxPromptLength: MAX_PROMPT_LENGTH,
|
|
300
|
-
maxPromptLengthWarning: PROMPT_LENGTH_WARNING,
|
|
301
|
-
promptLengthWarningCount: MAX_PROMPT_LENGTH - PROMPT_LENGTH_WARNING,
|
|
302
329
|
};
|
|
303
330
|
},
|
|
304
331
|
computed: {
|
|
@@ -407,6 +434,7 @@ export default {
|
|
|
407
434
|
if (!newVal && !this.isStreaming) {
|
|
408
435
|
this.displaySubmitButton = true; // Re-enable submit button when loading stops
|
|
409
436
|
}
|
|
437
|
+
this.isHidden = false;
|
|
410
438
|
},
|
|
411
439
|
isStreaming(newVal) {
|
|
412
440
|
if (!newVal && !this.isLoading) {
|
|
@@ -447,10 +475,14 @@ export default {
|
|
|
447
475
|
this.focusChatInput();
|
|
448
476
|
});
|
|
449
477
|
},
|
|
478
|
+
updateSize(e) {
|
|
479
|
+
this.$emit('chat-resize', e);
|
|
480
|
+
},
|
|
450
481
|
compositionEnd() {
|
|
451
482
|
this.compositionJustEnded = true;
|
|
452
483
|
},
|
|
453
484
|
hideChat() {
|
|
485
|
+
this.isHidden = true;
|
|
454
486
|
/**
|
|
455
487
|
* Emitted when clicking the cross in the title and the chat gets closed.
|
|
456
488
|
*/
|
|
@@ -513,7 +545,7 @@ export default {
|
|
|
513
545
|
focusChatInput() {
|
|
514
546
|
// This method is also called directly by consumers of this component
|
|
515
547
|
// https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/blob/dae2d4669ab4da327921492a2962beae8a05c290/webviews/vue2/gitlab_duo_chat/src/App.vue#L109
|
|
516
|
-
this.$refs.prompt?.$el?.
|
|
548
|
+
this.$refs.prompt?.$el?.focus();
|
|
517
549
|
},
|
|
518
550
|
onTrackFeedback(event) {
|
|
519
551
|
/**
|
|
@@ -667,222 +699,214 @@ export default {
|
|
|
667
699
|
event.preventDefault();
|
|
668
700
|
document.execCommand('redo');
|
|
669
701
|
},
|
|
670
|
-
remainingCharacterCountMessage(count) {
|
|
671
|
-
return `${count} characters remaining`;
|
|
672
|
-
},
|
|
673
|
-
overLimitCharacterCountMessage(count) {
|
|
674
|
-
return `${Math.abs(count)} characters over limit`;
|
|
675
|
-
},
|
|
676
702
|
},
|
|
677
703
|
i18n,
|
|
678
704
|
};
|
|
679
705
|
</script>
|
|
680
706
|
<template>
|
|
681
|
-
<
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
707
|
+
<component
|
|
708
|
+
:is="shouldRenderResizable ? 'vue-resizable' : 'div'"
|
|
709
|
+
:width="shouldRenderResizable ? dimensions.width : null"
|
|
710
|
+
:height="shouldRenderResizable ? dimensions.height : null"
|
|
711
|
+
:max-width="shouldRenderResizable ? dimensions.maxWidth : null"
|
|
712
|
+
:max-height="shouldRenderResizable ? dimensions.maxHeight : null"
|
|
713
|
+
:min-width="shouldRenderResizable ? dimensions.minWidth : null"
|
|
714
|
+
:left="shouldRenderResizable ? dimensions.left : null"
|
|
715
|
+
:top="shouldRenderResizable ? dimensions.top : null"
|
|
716
|
+
:fit-parent="true"
|
|
717
|
+
:min-height="shouldRenderResizable ? dimensions.minHeight : null"
|
|
718
|
+
:class="{
|
|
719
|
+
'duo-chat-resizable': shouldRenderResizable,
|
|
720
|
+
'non-resizable-wrapper': !shouldRenderResizable,
|
|
721
|
+
}"
|
|
722
|
+
:active="shouldRenderResizable ? ['l', 't', 'lt'] : null"
|
|
723
|
+
@resize:end="updateSize"
|
|
686
724
|
>
|
|
687
|
-
<
|
|
688
|
-
v-if="
|
|
689
|
-
|
|
690
|
-
:
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
@go-back="onGoBack"
|
|
698
|
-
@go-back-to-chat="onGoBackToChat"
|
|
699
|
-
@new-chat="onNewChat"
|
|
700
|
-
@close="hideChat"
|
|
701
|
-
>
|
|
702
|
-
<template #subheader>
|
|
703
|
-
<slot name="subheader"></slot>
|
|
704
|
-
</template>
|
|
705
|
-
</duo-chat-header>
|
|
706
|
-
|
|
707
|
-
<div
|
|
708
|
-
class="gl-flex gl-flex-1 gl-flex-grow gl-flex-col gl-overflow-y-auto gl-overscroll-contain gl-bg-inherit"
|
|
709
|
-
data-testid="chat-history"
|
|
710
|
-
@scroll="handleScrollingThrottled"
|
|
725
|
+
<aside
|
|
726
|
+
v-if="!isHidden"
|
|
727
|
+
id="chat-component"
|
|
728
|
+
:class="{
|
|
729
|
+
'resizable-content': shouldRenderResizable,
|
|
730
|
+
'duo-chat-drawer': !shouldRenderResizable,
|
|
731
|
+
}"
|
|
732
|
+
class="markdown-code-block duo-chat gl-bottom-0 gl-flex gl-max-h-full gl-flex-col"
|
|
733
|
+
role="complementary"
|
|
734
|
+
data-testid="chat-component"
|
|
711
735
|
>
|
|
712
|
-
<duo-chat-
|
|
713
|
-
v-if="
|
|
714
|
-
|
|
715
|
-
:
|
|
736
|
+
<duo-chat-header
|
|
737
|
+
v-if="showHeader"
|
|
738
|
+
ref="header"
|
|
739
|
+
:active-thread-id="activeThreadId"
|
|
740
|
+
:title="
|
|
741
|
+
isMultithreaded && currentView === 'list' ? $options.i18n.CHAT_HISTORY_TITLE : title
|
|
742
|
+
"
|
|
743
|
+
:subtitle="activeThreadTitleForView"
|
|
744
|
+
:is-multithreaded="isMultithreaded"
|
|
745
|
+
:current-view="currentView"
|
|
746
|
+
:should-render-resizable="shouldRenderResizable"
|
|
747
|
+
:badge-type="isMultithreaded ? null : badgeType"
|
|
748
|
+
@go-back="onGoBack"
|
|
749
|
+
@go-back-to-chat="onGoBackToChat"
|
|
716
750
|
@new-chat="onNewChat"
|
|
717
|
-
@select-thread="onSelectThread"
|
|
718
|
-
@delete-thread="onDeleteThread"
|
|
719
751
|
@close="hideChat"
|
|
720
|
-
/>
|
|
721
|
-
<transition-group
|
|
722
|
-
v-else
|
|
723
|
-
mode="out-in"
|
|
724
|
-
tag="section"
|
|
725
|
-
name="message"
|
|
726
|
-
class="duo-chat-history gl-mt-auto gl-p-5"
|
|
727
752
|
>
|
|
728
|
-
<
|
|
729
|
-
|
|
730
|
-
:key="`conversation-${index}`"
|
|
731
|
-
:enable-code-insertion="enableCodeInsertion"
|
|
732
|
-
:messages="conversation"
|
|
733
|
-
:canceled-request-ids="canceledRequestIds"
|
|
734
|
-
:show-delimiter="index > 0"
|
|
735
|
-
:trusted-urls="trustedUrls"
|
|
736
|
-
@track-feedback="onTrackFeedback"
|
|
737
|
-
@insert-code-snippet="onInsertCodeSnippet"
|
|
738
|
-
@copy-code-snippet="onCopyCodeSnippet"
|
|
739
|
-
@copy-message="onCopyMessage"
|
|
740
|
-
@get-context-item-content="onGetContextItemContent"
|
|
741
|
-
@open-file-path="onOpenFilePath"
|
|
742
|
-
/>
|
|
743
|
-
<template v-if="!hasMessages && !isLoading">
|
|
744
|
-
<div
|
|
745
|
-
key="empty-state-message"
|
|
746
|
-
class="duo-chat-message gl-rounded-bl-none gl-p-4 gl-leading-20 gl-text-gray-900 gl-break-anywhere"
|
|
747
|
-
data-testid="gl-duo-chat-empty-state"
|
|
748
|
-
>
|
|
749
|
-
<p v-if="emptyStateTitle" data-testid="gl-duo-chat-empty-state-title" class="gl-m-0">
|
|
750
|
-
{{ emptyStateTitle }}
|
|
751
|
-
</p>
|
|
752
|
-
<duo-chat-predefined-prompts
|
|
753
|
-
key="predefined-prompts"
|
|
754
|
-
:prompts="predefinedPrompts"
|
|
755
|
-
@click="sendPredefinedPrompt"
|
|
756
|
-
/>
|
|
757
|
-
</div>
|
|
753
|
+
<template #subheader>
|
|
754
|
+
<slot name="subheader"></slot>
|
|
758
755
|
</template>
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
756
|
+
</duo-chat-header>
|
|
757
|
+
|
|
758
|
+
<div
|
|
759
|
+
class="gl-flex gl-flex-1 gl-flex-grow gl-flex-col gl-overflow-y-auto gl-overscroll-contain gl-bg-inherit"
|
|
760
|
+
data-testid="chat-history"
|
|
761
|
+
@scroll="handleScrollingThrottled"
|
|
762
|
+
>
|
|
763
|
+
<duo-chat-threads
|
|
764
|
+
v-if="shouldShowThreadList"
|
|
765
|
+
:threads="threadList"
|
|
766
|
+
:preferred-locale="preferredLocale"
|
|
767
|
+
@new-chat="onNewChat"
|
|
768
|
+
@select-thread="onSelectThread"
|
|
769
|
+
@delete-thread="onDeleteThread"
|
|
770
|
+
@close="hideChat"
|
|
771
|
+
/>
|
|
772
|
+
<transition-group
|
|
773
|
+
v-else
|
|
774
|
+
mode="out-in"
|
|
775
|
+
tag="section"
|
|
776
|
+
name="message"
|
|
777
|
+
class="duo-chat-history gl-mt-auto gl-p-5"
|
|
778
|
+
>
|
|
779
|
+
<duo-chat-conversation
|
|
780
|
+
v-for="(conversation, index) in conversations"
|
|
781
|
+
:key="`conversation-${index}`"
|
|
782
|
+
:enable-code-insertion="enableCodeInsertion"
|
|
783
|
+
:messages="conversation"
|
|
784
|
+
:canceled-request-ids="canceledRequestIds"
|
|
785
|
+
:show-delimiter="index > 0"
|
|
786
|
+
:trusted-urls="trustedUrls"
|
|
787
|
+
@track-feedback="onTrackFeedback"
|
|
788
|
+
@insert-code-snippet="onInsertCodeSnippet"
|
|
789
|
+
@copy-code-snippet="onCopyCodeSnippet"
|
|
790
|
+
@copy-message="onCopyMessage"
|
|
791
|
+
@get-context-item-content="onGetContextItemContent"
|
|
792
|
+
@open-file-path="onOpenFilePath"
|
|
793
|
+
/>
|
|
794
|
+
<template v-if="!hasMessages && !isLoading">
|
|
795
|
+
<div
|
|
796
|
+
key="empty-state-message"
|
|
797
|
+
class="duo-chat-message gl-rounded-bl-none gl-p-4 gl-leading-20 gl-text-gray-900 gl-break-anywhere"
|
|
798
|
+
data-testid="gl-duo-chat-empty-state"
|
|
799
|
+
>
|
|
800
|
+
<p v-if="emptyStateTitle" data-testid="gl-duo-chat-empty-state-title" class="gl-m-0">
|
|
801
|
+
{{ emptyStateTitle }}
|
|
802
|
+
</p>
|
|
803
|
+
<duo-chat-predefined-prompts
|
|
804
|
+
key="predefined-prompts"
|
|
805
|
+
:prompts="predefinedPrompts"
|
|
806
|
+
@click="sendPredefinedPrompt"
|
|
807
|
+
/>
|
|
808
|
+
</div>
|
|
809
|
+
</template>
|
|
810
|
+
<duo-chat-loader v-if="isLoading" key="loader" :tool-name="toolName" />
|
|
811
|
+
<div key="anchor" ref="anchor" class="scroll-anchor"></div>
|
|
812
|
+
</transition-group>
|
|
813
|
+
</div>
|
|
814
|
+
<footer
|
|
815
|
+
v-if="isChatAvailable && !shouldShowThreadList"
|
|
816
|
+
data-testid="chat-footer"
|
|
817
|
+
class="duo-chat-drawer-footer gl-relative gl-z-2 gl-shrink-0 gl-border-0 gl-bg-default gl-pb-3"
|
|
818
|
+
:class="{ 'duo-chat-drawer-body-scrim-on-footer': !scrolledToBottom }"
|
|
819
|
+
>
|
|
820
|
+
<gl-form data-testid="chat-prompt-form" @submit.stop.prevent="sendChatPrompt">
|
|
821
|
+
<div class="gl-relative gl-max-w-full">
|
|
822
|
+
<!--
|
|
772
823
|
@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 }">` `<duo-chat-context-item-menu :ref="setRef" :open="isOpen" @close="onClose" @focus-prompt="focusPrompt" ...`
|
|
773
824
|
-->
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
</div>
|
|
782
|
-
|
|
783
|
-
<div
|
|
784
|
-
class="duo-chat-input gl-min-h-8 gl-max-w-full gl-grow gl-flex-col gl-rounded-bl-[12px] gl-rounded-br-[18px] gl-rounded-tl-[12px] gl-rounded-tr-[12px] gl-align-top"
|
|
785
|
-
>
|
|
786
|
-
<div
|
|
787
|
-
class="gl-flex gl-justify-between gl-border-0 gl-border-b-1 gl-border-solid gl-border-[#DCDCDE] gl-px-4 gl-py-4"
|
|
788
|
-
>
|
|
789
|
-
<div>{{ $options.i18n.CHAT_MODEL_PLACEHOLDER }}</div>
|
|
790
|
-
<div><slot name="agentic-switch"></slot></div>
|
|
825
|
+
<slot
|
|
826
|
+
name="context-items-menu"
|
|
827
|
+
:is-open="contextItemsMenuIsOpen"
|
|
828
|
+
:on-close="closeContextItemsMenuOpen"
|
|
829
|
+
:set-ref="setContextItemsMenuRef"
|
|
830
|
+
:focus-prompt="focusChatInput"
|
|
831
|
+
></slot>
|
|
791
832
|
</div>
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
body-class="!gl-p-2"
|
|
833
|
+
|
|
834
|
+
<gl-form-input-group>
|
|
835
|
+
<div
|
|
836
|
+
class="duo-chat-input gl-min-h-8 gl-max-w-full gl-grow gl-align-top"
|
|
837
|
+
:data-value="prompt"
|
|
798
838
|
>
|
|
799
|
-
<gl-
|
|
800
|
-
v-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
@click="selectSlashCommand(index)"
|
|
839
|
+
<gl-card
|
|
840
|
+
v-if="shouldShowSlashCommands"
|
|
841
|
+
ref="commands"
|
|
842
|
+
class="slash-commands !gl-absolute gl-w-full -gl-translate-y-full gl-list-none gl-pl-0 gl-shadow-md"
|
|
843
|
+
body-class="!gl-p-2"
|
|
805
844
|
>
|
|
806
|
-
<
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
</gl-dropdown-item>
|
|
813
|
-
</gl-card>
|
|
814
|
-
|
|
815
|
-
<gl-form-textarea
|
|
816
|
-
ref="prompt"
|
|
817
|
-
v-model="prompt"
|
|
818
|
-
data-testid="chat-prompt-input"
|
|
819
|
-
:textarea-classes="[
|
|
820
|
-
'!gl-h-full',
|
|
821
|
-
'!gl-bg-transparent',
|
|
822
|
-
'!gl-py-4',
|
|
823
|
-
'!gl-shadow-none',
|
|
824
|
-
'form-control',
|
|
825
|
-
'gl-form-input',
|
|
826
|
-
'gl-form-textarea',
|
|
827
|
-
{ 'gl-truncate': !prompt },
|
|
828
|
-
]"
|
|
829
|
-
:placeholder="inputPlaceholder"
|
|
830
|
-
:character-count-limit="maxPromptLength"
|
|
831
|
-
autofocus
|
|
832
|
-
@keydown.enter.exact.native.prevent
|
|
833
|
-
@keydown.ctrl.z.exact="handleUndo"
|
|
834
|
-
@keydown.meta.z.exact="handleUndo"
|
|
835
|
-
@keydown.ctrl.shift.z="handleRedo"
|
|
836
|
-
@keydown.meta.shift.z="handleRedo"
|
|
837
|
-
@keydown.ctrl.y="handleRedo"
|
|
838
|
-
@keydown.meta.y="handleRedo"
|
|
839
|
-
@keyup.native="onInputKeyup"
|
|
840
|
-
@compositionend="compositionEnd"
|
|
841
|
-
>
|
|
842
|
-
<template #remaining-character-count-text="{ count }">
|
|
843
|
-
<span
|
|
844
|
-
v-if="count <= promptLengthWarningCount"
|
|
845
|
-
class="gl-absolute gl-bottom-[-25px] gl-right-px gl-pr-3"
|
|
845
|
+
<gl-dropdown-item
|
|
846
|
+
v-for="(command, index) in filteredSlashCommands"
|
|
847
|
+
:key="command.name"
|
|
848
|
+
:class="{ 'active-command': index === activeCommandIndex }"
|
|
849
|
+
@mouseenter.native="activeCommandIndex = index"
|
|
850
|
+
@click="selectSlashCommand(index)"
|
|
846
851
|
>
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
</
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
852
|
+
<span class="gl-flex gl-justify-between">
|
|
853
|
+
<span class="gl-block">{{ command.name }}</span>
|
|
854
|
+
<small class="gl-pl-3 gl-text-right gl-italic gl-text-subtle">{{
|
|
855
|
+
command.description
|
|
856
|
+
}}</small>
|
|
857
|
+
</span>
|
|
858
|
+
</gl-dropdown-item>
|
|
859
|
+
</gl-card>
|
|
860
|
+
|
|
861
|
+
<gl-form-textarea
|
|
862
|
+
ref="prompt"
|
|
863
|
+
v-model="prompt"
|
|
864
|
+
data-testid="chat-prompt-input"
|
|
865
|
+
class="gl-absolute !gl-h-full gl-rounded-br-none gl-rounded-tr-none !gl-bg-transparent !gl-py-4 !gl-shadow-none"
|
|
866
|
+
:class="{ 'gl-truncate': !prompt }"
|
|
867
|
+
:placeholder="inputPlaceholder"
|
|
868
|
+
autofocus
|
|
869
|
+
@keydown.enter.exact.native.prevent
|
|
870
|
+
@keydown.ctrl.z.exact="handleUndo"
|
|
871
|
+
@keydown.meta.z.exact="handleUndo"
|
|
872
|
+
@keydown.ctrl.shift.z="handleRedo"
|
|
873
|
+
@keydown.meta.shift.z="handleRedo"
|
|
874
|
+
@keydown.ctrl.y="handleRedo"
|
|
875
|
+
@keydown.meta.y="handleRedo"
|
|
876
|
+
@keyup.native="onInputKeyup"
|
|
877
|
+
@compositionend="compositionEnd"
|
|
878
|
+
/>
|
|
879
|
+
</div>
|
|
880
|
+
<template #append>
|
|
881
|
+
<gl-button
|
|
882
|
+
v-if="displaySubmitButton"
|
|
883
|
+
icon="paper-airplane"
|
|
884
|
+
category="primary"
|
|
885
|
+
variant="confirm"
|
|
886
|
+
class="!gl-absolute gl-bottom-2 gl-right-2 !gl-rounded-full"
|
|
887
|
+
type="submit"
|
|
888
|
+
data-testid="chat-prompt-submit-button"
|
|
889
|
+
:disabled="isPromptEmpty"
|
|
890
|
+
:aria-label="$options.i18n.CHAT_SUBMIT_LABEL"
|
|
891
|
+
/>
|
|
892
|
+
<gl-button
|
|
893
|
+
v-else
|
|
894
|
+
icon="stop"
|
|
895
|
+
category="primary"
|
|
896
|
+
variant="default"
|
|
897
|
+
class="!gl-absolute gl-bottom-2 gl-right-2 !gl-rounded-full"
|
|
898
|
+
data-testid="chat-prompt-cancel-button"
|
|
899
|
+
:aria-label="$options.i18n.CHAT_CANCEL_LABEL"
|
|
900
|
+
@click="cancelPrompt"
|
|
901
|
+
/>
|
|
902
|
+
</template>
|
|
903
|
+
</gl-form-input-group>
|
|
904
|
+
</gl-form>
|
|
905
|
+
<slot name="footer-controls"></slot>
|
|
906
|
+
<p class="gl-mb-0 gl-mt-3 gl-px-4 gl-text-sm gl-text-secondary">
|
|
907
|
+
{{ $options.i18n.CHAT_DISCLAMER }}
|
|
908
|
+
</p>
|
|
909
|
+
</footer>
|
|
910
|
+
</aside>
|
|
911
|
+
</component>
|
|
888
912
|
</template>
|
package/src/index.js
CHANGED
|
@@ -42,7 +42,5 @@ export { InsertCodeSnippetElement as DuoChatInsertCodeSnippetElement } from './c
|
|
|
42
42
|
export { default as DuoNavigationBar } from './components/ui/duo_navigation_bar/duo_navigation_bar.vue';
|
|
43
43
|
export { default as DuoRecentCollapsible } from './components/ui/duo_recent_collapsible/duo_recent_collapsible.vue';
|
|
44
44
|
export { default as DuoRecentContent } from './components/ui/duo_recent_content/duo_recent_content.vue';
|
|
45
|
-
export { default as DuoLayout } from './components/ui/duo_layout/duo_layout.vue';
|
|
46
|
-
export { default as SideRail } from './components/ui/side_rail/side_rail.vue';
|
|
47
45
|
|
|
48
46
|
export { addDuoMarkdownPlugin } from './components/chat/markdown_renderer';
|
package/translations.js
CHANGED
|
@@ -7,12 +7,12 @@ export default {
|
|
|
7
7
|
'AgenticDuoChat.chatDefaultPredefinedPromptsCreateTemplate': 'How do I create a template?',
|
|
8
8
|
'AgenticDuoChat.chatDefaultPredefinedPromptsForkProject': 'How do I fork a project?',
|
|
9
9
|
'AgenticDuoChat.chatDefaultTitle': 'GitLab Duo Agentic Chat',
|
|
10
|
-
'AgenticDuoChat.chatDisclamer':
|
|
10
|
+
'AgenticDuoChat.chatDisclamer':
|
|
11
|
+
'Chat can autonomously change code. Responses and changes can be inaccurate. Review carefully.',
|
|
11
12
|
'AgenticDuoChat.chatEmptyStateTitle':
|
|
12
13
|
'👋 I am GitLab Duo Agentic Chat, your personal AI-powered assistant. How can I help you today?',
|
|
13
14
|
'AgenticDuoChat.chatHistoryTitle': 'Chat history',
|
|
14
|
-
'AgenticDuoChat.
|
|
15
|
-
'AgenticDuoChat.chatPromptPlaceholderDefault': "Let's work through this together...",
|
|
15
|
+
'AgenticDuoChat.chatPromptPlaceholderDefault': 'GitLab Duo Agentic Chat',
|
|
16
16
|
'AgenticDuoChat.chatPromptPlaceholderWithCommands': 'Type /help to learn more',
|
|
17
17
|
'AgenticDuoChat.chatSubmitLabel': 'Send chat message.',
|
|
18
18
|
'AgenticDuoChat.overLimitCharacterCountMessage': null,
|
|
@@ -67,10 +67,9 @@ export default {
|
|
|
67
67
|
'👋 I am GitLab Duo Chat, your personal AI-powered assistant. How can I help you today?',
|
|
68
68
|
'DuoChat.chatHistoryInfo': 'Inactive chats are deleted after 30 days.',
|
|
69
69
|
'DuoChat.chatHistoryToolTip': 'Chat history',
|
|
70
|
-
'DuoChat.chatModelPlaceholder': 'GitLab Duo Chat',
|
|
71
70
|
'DuoChat.chatNewLabel': 'New chat',
|
|
72
71
|
'DuoChat.chatNewToolTip': 'New chat',
|
|
73
|
-
'DuoChat.chatPromptPlaceholderDefault':
|
|
72
|
+
'DuoChat.chatPromptPlaceholderDefault': 'GitLab Duo Chat',
|
|
74
73
|
'DuoChat.chatPromptPlaceholderWithCommands': 'Type /help to learn more',
|
|
75
74
|
'DuoChat.chatSubmitLabel': 'Send chat message.',
|
|
76
75
|
'DuoChat.chatTitle': 'GitLab Duo Chat',
|