@gitlab/duo-ui 10.20.0 → 10.22.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/agentic_chat/agentic_duo_chat.js +18 -37
- package/dist/components/chat/components/duo_chat_header/duo_chat_header.js +4 -4
- package/dist/components/chat/components/duo_chat_message_tool_approval/components/create_commit_tool_params.js +148 -0
- package/dist/components/chat/components/duo_chat_message_tool_approval/components/create_issue_tool_params.js +88 -0
- package/dist/components/chat/components/duo_chat_message_tool_approval/components/create_merge_request_tool_params.js +83 -0
- package/dist/components/chat/components/duo_chat_message_tool_approval/components/pre_block.js +38 -0
- package/dist/components/chat/components/duo_chat_message_tool_approval/components/run_command_tool_params.js +62 -0
- package/dist/components/chat/components/duo_chat_message_tool_approval/message_tool_approval.js +46 -8
- package/dist/components/chat/duo_chat.js +35 -54
- package/dist/components/chat/mock_data.js +85 -1
- package/dist/components/ui/duo_layout/duo_layout.js +100 -0
- package/dist/components/ui/side_rail/side_rail.js +67 -0
- package/dist/components.css +1 -1
- package/dist/components.css.map +1 -1
- package/dist/index.js +2 -0
- package/dist/tailwind.css +1 -1
- package/dist/tailwind.css.map +1 -1
- package/dist/utils/object.js +9 -0
- package/package.json +5 -4
- package/src/components/agentic_chat/agentic_duo_chat.vue +210 -244
- package/src/components/chat/components/duo_chat_header/duo_chat_header.vue +24 -22
- package/src/components/chat/components/duo_chat_message_tool_approval/components/create_commit_tool_params.vue +155 -0
- package/src/components/chat/components/duo_chat_message_tool_approval/components/create_issue_tool_params.vue +80 -0
- package/src/components/chat/components/duo_chat_message_tool_approval/components/create_merge_request_tool_params.vue +74 -0
- package/src/components/chat/components/duo_chat_message_tool_approval/components/pre_block.vue +5 -0
- package/src/components/chat/components/duo_chat_message_tool_approval/components/run_command_tool_params.vue +30 -0
- package/src/components/chat/components/duo_chat_message_tool_approval/message_tool_approval.vue +143 -88
- package/src/components/chat/duo_chat.scss +1 -2
- package/src/components/chat/duo_chat.vue +214 -238
- package/src/components/chat/mock_data.js +99 -0
- package/src/components/ui/duo_layout/duo_layout.md +0 -0
- package/src/components/ui/duo_layout/duo_layout.vue +95 -0
- package/src/components/ui/side_rail/side_rail.vue +56 -0
- package/src/index.js +2 -0
- package/src/utils/object.js +4 -0
- package/translations.js +29 -6
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import throttle from 'lodash/throttle';
|
|
3
|
-
import VueResizable from 'vue-resizable';
|
|
4
3
|
|
|
5
4
|
import {
|
|
6
5
|
GlButton,
|
|
7
6
|
GlDropdownItem,
|
|
8
7
|
GlCard,
|
|
9
|
-
GlAlert,
|
|
10
|
-
GlFormInputGroup,
|
|
11
8
|
GlFormTextarea,
|
|
12
9
|
GlForm,
|
|
13
|
-
GlExperimentBadge,
|
|
14
10
|
GlSafeHtmlDirective as SafeHtml,
|
|
15
11
|
} from '@gitlab/ui';
|
|
16
12
|
|
|
@@ -38,7 +34,7 @@ export const i18n = {
|
|
|
38
34
|
CHAT_HISTORY_TITLE: translate('AgenticDuoChat.chatHistoryTitle', 'Chat history'),
|
|
39
35
|
CHAT_DISCLAMER: translate(
|
|
40
36
|
'AgenticDuoChat.chatDisclamer',
|
|
41
|
-
'
|
|
37
|
+
'Responses may be inaccurate. Verify before use.'
|
|
42
38
|
),
|
|
43
39
|
CHAT_EMPTY_STATE_TITLE: translate(
|
|
44
40
|
'AgenticDuoChat.chatEmptyStateTitle',
|
|
@@ -46,6 +42,10 @@ export const i18n = {
|
|
|
46
42
|
),
|
|
47
43
|
CHAT_PROMPT_PLACEHOLDER_DEFAULT: translate(
|
|
48
44
|
'AgenticDuoChat.chatPromptPlaceholderDefault',
|
|
45
|
+
"Let's work through this together..."
|
|
46
|
+
),
|
|
47
|
+
CHAT_MODEL_PLACEHOLDER: translate(
|
|
48
|
+
'AgenticDuoChat.chatModelPlaceholder',
|
|
49
49
|
'GitLab Duo Agentic Chat'
|
|
50
50
|
),
|
|
51
51
|
CHAT_PROMPT_PLACEHOLDER_WITH_COMMANDS: translate(
|
|
@@ -102,11 +102,8 @@ export default {
|
|
|
102
102
|
name: 'DuoChat',
|
|
103
103
|
components: {
|
|
104
104
|
GlButton,
|
|
105
|
-
GlAlert,
|
|
106
|
-
GlFormInputGroup,
|
|
107
105
|
GlFormTextarea,
|
|
108
106
|
GlForm,
|
|
109
|
-
GlExperimentBadge,
|
|
110
107
|
DuoChatLoader,
|
|
111
108
|
DuoChatPredefinedPrompts,
|
|
112
109
|
DuoChatConversation,
|
|
@@ -114,7 +111,6 @@ export default {
|
|
|
114
111
|
DuoChatThreads,
|
|
115
112
|
GlCard,
|
|
116
113
|
GlDropdownItem,
|
|
117
|
-
VueResizable,
|
|
118
114
|
},
|
|
119
115
|
directives: {
|
|
120
116
|
SafeHtml,
|
|
@@ -343,7 +339,6 @@ export default {
|
|
|
343
339
|
},
|
|
344
340
|
data() {
|
|
345
341
|
return {
|
|
346
|
-
isHidden: false,
|
|
347
342
|
prompt: '',
|
|
348
343
|
scrolledToBottom: true,
|
|
349
344
|
activeCommandIndex: 0,
|
|
@@ -461,7 +456,6 @@ export default {
|
|
|
461
456
|
if (!loading && !this.isStreaming) {
|
|
462
457
|
this.canSubmit = true; // Re-enable submit button when loading stops
|
|
463
458
|
}
|
|
464
|
-
this.isHidden = false;
|
|
465
459
|
},
|
|
466
460
|
isStreaming(streaming) {
|
|
467
461
|
if (!streaming && !this.isLoading) {
|
|
@@ -502,14 +496,10 @@ export default {
|
|
|
502
496
|
this.focusChatInput();
|
|
503
497
|
});
|
|
504
498
|
},
|
|
505
|
-
updateSize(e) {
|
|
506
|
-
this.$emit('chat-resize', e);
|
|
507
|
-
},
|
|
508
499
|
compositionEnd() {
|
|
509
500
|
this.compositionJustEnded = true;
|
|
510
501
|
},
|
|
511
502
|
hideChat() {
|
|
512
|
-
this.isHidden = true;
|
|
513
503
|
/**
|
|
514
504
|
* Emitted when clicking the cross in the title and the chat gets closed.
|
|
515
505
|
*/
|
|
@@ -765,245 +755,221 @@ export default {
|
|
|
765
755
|
};
|
|
766
756
|
</script>
|
|
767
757
|
<template>
|
|
768
|
-
<
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
:max-height="shouldRenderResizable ? dimensions.maxHeight : null"
|
|
774
|
-
:min-width="shouldRenderResizable ? dimensions.minWidth : null"
|
|
775
|
-
:left="shouldRenderResizable ? dimensions.left : null"
|
|
776
|
-
:top="shouldRenderResizable ? dimensions.top : null"
|
|
777
|
-
:fit-parent="true"
|
|
778
|
-
:min-height="shouldRenderResizable ? dimensions.minHeight : null"
|
|
779
|
-
:class="{
|
|
780
|
-
'duo-chat-resizable': shouldRenderResizable,
|
|
781
|
-
'non-resizable-wrapper': !shouldRenderResizable,
|
|
782
|
-
}"
|
|
783
|
-
:active="shouldRenderResizable ? ['l', 't', 'lt'] : null"
|
|
784
|
-
@resize:end="updateSize"
|
|
758
|
+
<div
|
|
759
|
+
id="chat-component"
|
|
760
|
+
class="markdown-code-block duo-chat gl-bottom-0 gl-flex gl-max-h-full gl-flex-col"
|
|
761
|
+
role="complementary"
|
|
762
|
+
data-testid="chat-component"
|
|
785
763
|
>
|
|
786
|
-
<
|
|
787
|
-
v-if="
|
|
788
|
-
|
|
789
|
-
:
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
764
|
+
<duo-chat-header
|
|
765
|
+
v-if="showHeader"
|
|
766
|
+
ref="header"
|
|
767
|
+
:active-thread-id="activeThreadId"
|
|
768
|
+
:title="isMultithreaded && currentView === 'list' ? $options.i18n.CHAT_HISTORY_TITLE : title"
|
|
769
|
+
:subtitle="activeThreadTitleForView"
|
|
770
|
+
:error="error"
|
|
771
|
+
:is-multithreaded="isMultithreaded"
|
|
772
|
+
:current-view="currentView"
|
|
773
|
+
:should-render-resizable="shouldRenderResizable"
|
|
774
|
+
:badge-type="isMultithreaded ? null : badgeType"
|
|
775
|
+
:session-id="sessionId"
|
|
776
|
+
:agents="agents"
|
|
777
|
+
@go-back="onGoBack"
|
|
778
|
+
@new-chat="onNewChat"
|
|
779
|
+
@close="hideChat"
|
|
780
|
+
>
|
|
781
|
+
<template #subheader>
|
|
782
|
+
<slot name="subheader"></slot>
|
|
783
|
+
</template>
|
|
784
|
+
</duo-chat-header>
|
|
785
|
+
|
|
786
|
+
<div
|
|
787
|
+
class="gl-flex gl-flex-1 gl-flex-grow gl-flex-col gl-overflow-y-auto gl-overscroll-contain gl-bg-inherit"
|
|
788
|
+
data-testid="chat-history"
|
|
789
|
+
@scroll="handleScrollingThrottled"
|
|
796
790
|
>
|
|
797
|
-
<duo-chat-
|
|
798
|
-
v-if="
|
|
799
|
-
|
|
800
|
-
:
|
|
801
|
-
:title="
|
|
802
|
-
isMultithreaded && currentView === 'list' ? $options.i18n.CHAT_HISTORY_TITLE : title
|
|
803
|
-
"
|
|
804
|
-
:subtitle="activeThreadTitleForView"
|
|
805
|
-
:error="error"
|
|
806
|
-
:is-multithreaded="isMultithreaded"
|
|
807
|
-
:current-view="currentView"
|
|
808
|
-
:should-render-resizable="shouldRenderResizable"
|
|
809
|
-
:badge-type="isMultithreaded ? null : badgeType"
|
|
810
|
-
:session-id="sessionId"
|
|
811
|
-
:agents="agents"
|
|
812
|
-
@go-back="onGoBack"
|
|
791
|
+
<duo-chat-threads
|
|
792
|
+
v-if="shouldShowThreadList"
|
|
793
|
+
:threads="threadList"
|
|
794
|
+
:preferred-locale="preferredLocale"
|
|
813
795
|
@new-chat="onNewChat"
|
|
796
|
+
@select-thread="onSelectThread"
|
|
797
|
+
@delete-thread="onDeleteThread"
|
|
814
798
|
@close="hideChat"
|
|
799
|
+
/>
|
|
800
|
+
<transition-group
|
|
801
|
+
v-else
|
|
802
|
+
mode="out-in"
|
|
803
|
+
tag="section"
|
|
804
|
+
name="message"
|
|
805
|
+
class="duo-chat-history gl-mt-auto gl-p-5"
|
|
815
806
|
>
|
|
816
|
-
<
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
@
|
|
831
|
-
@
|
|
832
|
-
@
|
|
833
|
-
@close="hideChat"
|
|
807
|
+
<duo-chat-conversation
|
|
808
|
+
v-for="(conversation, index) in conversations"
|
|
809
|
+
:key="`conversation-${index}`"
|
|
810
|
+
:enable-code-insertion="enableCodeInsertion"
|
|
811
|
+
:messages="conversation"
|
|
812
|
+
:show-delimiter="index > 0"
|
|
813
|
+
:with-feedback="withFeedback"
|
|
814
|
+
:is-tool-approval-processing="isToolApprovalProcessing"
|
|
815
|
+
:working-directory="workingDirectory"
|
|
816
|
+
@track-feedback="onTrackFeedback"
|
|
817
|
+
@insert-code-snippet="onInsertCodeSnippet"
|
|
818
|
+
@copy-code-snippet="onCopyCodeSnippet"
|
|
819
|
+
@copy-message="onCopyMessage"
|
|
820
|
+
@get-context-item-content="onGetContextItemContent"
|
|
821
|
+
@approve-tool="onApproveToolCall"
|
|
822
|
+
@deny-tool="onDenyToolCall"
|
|
823
|
+
@open-file-path="onOpenFilePath"
|
|
834
824
|
/>
|
|
835
|
-
<
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
data-testid="gl-duo-chat-empty-state"
|
|
865
|
-
>
|
|
866
|
-
<p v-if="emptyStateTitle" data-testid="gl-duo-chat-empty-state-title" class="gl-m-0">
|
|
867
|
-
{{ emptyStateTitle }}
|
|
868
|
-
</p>
|
|
869
|
-
<duo-chat-predefined-prompts
|
|
870
|
-
key="predefined-prompts"
|
|
871
|
-
:prompts="predefinedPrompts"
|
|
872
|
-
@click="sendPredefinedPrompt"
|
|
873
|
-
/>
|
|
874
|
-
</div>
|
|
875
|
-
</template>
|
|
876
|
-
<duo-chat-loader v-if="isLoading" key="loader" :tool-name="toolName" />
|
|
877
|
-
<div key="anchor" ref="anchor" class="scroll-anchor"></div>
|
|
878
|
-
</transition-group>
|
|
879
|
-
</div>
|
|
880
|
-
<footer
|
|
881
|
-
v-if="isChatAvailable && !shouldShowThreadList"
|
|
882
|
-
data-testid="chat-footer"
|
|
883
|
-
class="duo-chat-drawer-footer gl-relative gl-z-2 gl-shrink-0 gl-border-0 gl-bg-default gl-pb-3"
|
|
884
|
-
:class="{ 'duo-chat-drawer-body-scrim-on-footer': !scrolledToBottom }"
|
|
885
|
-
>
|
|
886
|
-
<gl-form data-testid="chat-prompt-form" @submit.stop.prevent="sendChatPrompt">
|
|
887
|
-
<div class="gl-relative gl-max-w-full">
|
|
888
|
-
<!--
|
|
825
|
+
<template v-if="!hasMessages && !isLoading">
|
|
826
|
+
<div
|
|
827
|
+
key="empty-state-message"
|
|
828
|
+
class="duo-chat-message gl-rounded-bl-none gl-leading-20 gl-text-gray-900 gl-break-anywhere"
|
|
829
|
+
data-testid="gl-duo-chat-empty-state"
|
|
830
|
+
>
|
|
831
|
+
<p v-if="emptyStateTitle" data-testid="gl-duo-chat-empty-state-title" class="gl-m-0">
|
|
832
|
+
{{ emptyStateTitle }}
|
|
833
|
+
</p>
|
|
834
|
+
<duo-chat-predefined-prompts
|
|
835
|
+
key="predefined-prompts"
|
|
836
|
+
:prompts="predefinedPrompts"
|
|
837
|
+
@click="sendPredefinedPrompt"
|
|
838
|
+
/>
|
|
839
|
+
</div>
|
|
840
|
+
</template>
|
|
841
|
+
<duo-chat-loader v-if="isLoading" key="loader" :tool-name="toolName" />
|
|
842
|
+
<div key="anchor" ref="anchor" class="scroll-anchor"></div>
|
|
843
|
+
</transition-group>
|
|
844
|
+
</div>
|
|
845
|
+
<footer
|
|
846
|
+
v-if="isChatAvailable && !shouldShowThreadList"
|
|
847
|
+
data-testid="chat-footer"
|
|
848
|
+
class="duo-chat-drawer-footer gl-relative gl-z-2 gl-shrink-0 gl-border-0 gl-bg-default gl-pb-3"
|
|
849
|
+
:class="{ 'duo-chat-drawer-body-scrim-on-footer': !scrolledToBottom }"
|
|
850
|
+
>
|
|
851
|
+
<gl-form data-testid="chat-prompt-form" @submit.stop.prevent="sendChatPrompt">
|
|
852
|
+
<div class="gl-relative gl-max-w-full">
|
|
853
|
+
<!--
|
|
889
854
|
@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" ...`
|
|
890
855
|
-->
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
856
|
+
<slot
|
|
857
|
+
name="context-items-menu"
|
|
858
|
+
:is-open="contextItemsMenuIsOpen"
|
|
859
|
+
:on-close="closeContextItemsMenuOpen"
|
|
860
|
+
:set-ref="setContextItemsMenuRef"
|
|
861
|
+
:focus-prompt="focusChatInput"
|
|
862
|
+
></slot>
|
|
863
|
+
</div>
|
|
864
|
+
|
|
865
|
+
<div
|
|
866
|
+
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"
|
|
867
|
+
>
|
|
868
|
+
<div
|
|
869
|
+
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"
|
|
870
|
+
>
|
|
871
|
+
<div>{{ $options.i18n.CHAT_MODEL_PLACEHOLDER }}</div>
|
|
872
|
+
<div><slot name="agentic-switch"></slot></div>
|
|
898
873
|
</div>
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
874
|
+
<div :data-value="prompt" class="gl-h-[40px] gl-grow">
|
|
875
|
+
<gl-card
|
|
876
|
+
v-if="shouldShowSlashCommands"
|
|
877
|
+
ref="commands"
|
|
878
|
+
class="slash-commands !gl-absolute gl-w-full -gl-translate-y-full gl-list-none gl-pl-0 gl-shadow-md"
|
|
879
|
+
body-class="!gl-p-2"
|
|
904
880
|
>
|
|
905
|
-
<gl-
|
|
906
|
-
v-
|
|
907
|
-
|
|
908
|
-
class="
|
|
909
|
-
|
|
881
|
+
<gl-dropdown-item
|
|
882
|
+
v-for="(command, index) in filteredSlashCommands"
|
|
883
|
+
:key="command.name"
|
|
884
|
+
:class="{ 'active-command': index === activeCommandIndex }"
|
|
885
|
+
@mouseenter.native="activeCommandIndex = index"
|
|
886
|
+
@click="selectSlashCommand(index)"
|
|
910
887
|
>
|
|
911
|
-
<gl-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
888
|
+
<span class="gl-flex gl-justify-between">
|
|
889
|
+
<span class="gl-block">{{ command.name }}</span>
|
|
890
|
+
<small class="gl-pl-3 gl-text-right gl-italic gl-text-subtle">{{
|
|
891
|
+
command.description
|
|
892
|
+
}}</small>
|
|
893
|
+
</span>
|
|
894
|
+
</gl-dropdown-item>
|
|
895
|
+
</gl-card>
|
|
896
|
+
|
|
897
|
+
<gl-form-textarea
|
|
898
|
+
ref="prompt"
|
|
899
|
+
v-model="prompt"
|
|
900
|
+
:disabled="!canSubmit"
|
|
901
|
+
data-testid="chat-prompt-input"
|
|
902
|
+
:placeholder="inputPlaceholder"
|
|
903
|
+
:character-count-limit="maxPromptLength"
|
|
904
|
+
:textarea-classes="[
|
|
905
|
+
'!gl-h-full',
|
|
906
|
+
'!gl-bg-transparent',
|
|
907
|
+
'!gl-py-4',
|
|
908
|
+
'!gl-shadow-none',
|
|
909
|
+
'form-control',
|
|
910
|
+
'gl-form-input',
|
|
911
|
+
'gl-form-textarea',
|
|
912
|
+
{ 'gl-truncate': !prompt },
|
|
913
|
+
]"
|
|
914
|
+
aria-label="Chat prompt input"
|
|
915
|
+
autofocus
|
|
916
|
+
@keydown.enter.exact.native.prevent
|
|
917
|
+
@keydown.ctrl.z.exact="handleUndo"
|
|
918
|
+
@keydown.meta.z.exact="handleUndo"
|
|
919
|
+
@keydown.ctrl.shift.z.exact="handleRedo"
|
|
920
|
+
@keydown.meta.shift.z.exact="handleRedo"
|
|
921
|
+
@keydown.ctrl.y.exact="handleRedo"
|
|
922
|
+
@keydown.meta.y.exact="handleRedo"
|
|
923
|
+
@keyup.native="onInputKeyup"
|
|
924
|
+
@compositionend="compositionEnd"
|
|
925
|
+
>
|
|
926
|
+
<template #remaining-character-count-text="{ count }">
|
|
927
|
+
<span
|
|
928
|
+
v-if="count <= promptLengthWarningCount"
|
|
929
|
+
class="gl-absolute gl-bottom-[-25px] gl-right-px gl-pr-3"
|
|
917
930
|
>
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
</
|
|
925
|
-
</
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
class="gl-absolute gl-bottom-[-25px] gl-right-px gl-pr-3"
|
|
963
|
-
>
|
|
964
|
-
{{ remainingCharacterCountMessage(count) }}
|
|
965
|
-
</span>
|
|
966
|
-
</template>
|
|
967
|
-
<template #character-count-over-limit-text="{ count }">
|
|
968
|
-
<span class="gl-absolute gl-bottom-[-25px] gl-right-px gl-pr-3">{{
|
|
969
|
-
overLimitCharacterCountMessage(count)
|
|
970
|
-
}}</span>
|
|
971
|
-
</template>
|
|
972
|
-
</gl-form-textarea>
|
|
973
|
-
</div>
|
|
974
|
-
<template #append>
|
|
975
|
-
<gl-button
|
|
976
|
-
v-if="canSubmit"
|
|
977
|
-
icon="paper-airplane"
|
|
978
|
-
category="primary"
|
|
979
|
-
variant="confirm"
|
|
980
|
-
class="!gl-absolute gl-bottom-2 gl-right-2 !gl-rounded-full"
|
|
981
|
-
type="submit"
|
|
982
|
-
:disabled="isPromptEmpty || !hasValidPrompt"
|
|
983
|
-
data-testid="chat-prompt-submit-button"
|
|
984
|
-
:aria-label="$options.i18n.CHAT_SUBMIT_LABEL"
|
|
985
|
-
/>
|
|
986
|
-
<gl-button
|
|
987
|
-
v-else
|
|
988
|
-
icon="stop"
|
|
989
|
-
category="primary"
|
|
990
|
-
variant="default"
|
|
991
|
-
class="!gl-absolute gl-bottom-2 gl-right-2 !gl-rounded-full"
|
|
992
|
-
data-testid="chat-prompt-cancel-button"
|
|
993
|
-
:aria-label="$options.i18n.CHAT_CANCEL_LABEL"
|
|
994
|
-
@click="cancelPrompt"
|
|
995
|
-
/>
|
|
996
|
-
</template>
|
|
997
|
-
</gl-form-input-group>
|
|
998
|
-
</gl-form>
|
|
999
|
-
<slot name="footer-controls"></slot>
|
|
1000
|
-
<p
|
|
1001
|
-
class="gl-mb-0 gl-mt-3 gl-px-4 gl-text-sm gl-text-secondary"
|
|
1002
|
-
:class="{ 'gl-mt-6 sm:gl-mt-3 sm:gl-max-w-1/2': prompt.length >= maxPromptLengthWarning }"
|
|
1003
|
-
>
|
|
1004
|
-
{{ $options.i18n.CHAT_DISCLAMER }}
|
|
1005
|
-
</p>
|
|
1006
|
-
</footer>
|
|
1007
|
-
</aside>
|
|
1008
|
-
</component>
|
|
931
|
+
{{ remainingCharacterCountMessage(count) }}
|
|
932
|
+
</span>
|
|
933
|
+
</template>
|
|
934
|
+
<template #character-count-over-limit-text="{ count }">
|
|
935
|
+
<span class="gl-absolute gl-bottom-[-25px] gl-right-px gl-pr-3">{{
|
|
936
|
+
overLimitCharacterCountMessage(count)
|
|
937
|
+
}}</span>
|
|
938
|
+
</template>
|
|
939
|
+
</gl-form-textarea>
|
|
940
|
+
</div>
|
|
941
|
+
<div class="gl-flex gl-justify-end gl-px-3 gl-pb-3">
|
|
942
|
+
<gl-button
|
|
943
|
+
v-if="canSubmit"
|
|
944
|
+
icon="paper-airplane"
|
|
945
|
+
category="primary"
|
|
946
|
+
variant="confirm"
|
|
947
|
+
class="gl-bottom-2 gl-right-2 gl-ml-auto !gl-rounded-full"
|
|
948
|
+
type="submit"
|
|
949
|
+
:disabled="isPromptEmpty || !hasValidPrompt"
|
|
950
|
+
data-testid="chat-prompt-submit-button"
|
|
951
|
+
:aria-label="$options.i18n.CHAT_SUBMIT_LABEL"
|
|
952
|
+
/>
|
|
953
|
+
<gl-button
|
|
954
|
+
v-else
|
|
955
|
+
icon="stop"
|
|
956
|
+
category="primary"
|
|
957
|
+
variant="default"
|
|
958
|
+
class="gl-bottom-2 gl-right-2 !gl-rounded-full"
|
|
959
|
+
data-testid="chat-prompt-cancel-button"
|
|
960
|
+
:aria-label="$options.i18n.CHAT_CANCEL_LABEL"
|
|
961
|
+
@click="cancelPrompt"
|
|
962
|
+
/>
|
|
963
|
+
</div>
|
|
964
|
+
</div>
|
|
965
|
+
</gl-form>
|
|
966
|
+
<slot name="footer-controls"></slot>
|
|
967
|
+
<p
|
|
968
|
+
class="gl-mb-0 gl-mt-3 gl-px-4 gl-text-sm gl-text-secondary"
|
|
969
|
+
:class="{ 'gl-mt-6 sm:gl-mt-3 sm:gl-max-w-1/2': prompt.length >= maxPromptLengthWarning }"
|
|
970
|
+
>
|
|
971
|
+
{{ $options.i18n.CHAT_DISCLAMER }}
|
|
972
|
+
</p>
|
|
973
|
+
</footer>
|
|
974
|
+
</div>
|
|
1009
975
|
</template>
|
|
@@ -3,10 +3,10 @@ import Vue from 'vue';
|
|
|
3
3
|
import {
|
|
4
4
|
GlAlert,
|
|
5
5
|
GlBadge,
|
|
6
|
+
GlAvatar,
|
|
6
7
|
GlButton,
|
|
7
8
|
GlDropdown,
|
|
8
9
|
GlDropdownItem,
|
|
9
|
-
GlExperimentBadge,
|
|
10
10
|
GlSafeHtmlDirective as SafeHtml,
|
|
11
11
|
GlTooltipDirective,
|
|
12
12
|
GlToast,
|
|
@@ -43,10 +43,10 @@ export default {
|
|
|
43
43
|
components: {
|
|
44
44
|
GlAlert,
|
|
45
45
|
GlBadge,
|
|
46
|
+
GlAvatar,
|
|
46
47
|
GlButton,
|
|
47
48
|
GlDropdown,
|
|
48
49
|
GlDropdownItem,
|
|
49
|
-
GlExperimentBadge,
|
|
50
50
|
GlDisclosureDropdown,
|
|
51
51
|
},
|
|
52
52
|
directives: {
|
|
@@ -140,19 +140,31 @@ export default {
|
|
|
140
140
|
|
|
141
141
|
<template>
|
|
142
142
|
<header data-testid="chat-header" class="gl-border-b gl-shrink-0 gl-bg-default gl-p-0">
|
|
143
|
+
<div class="gl-border-b gl-flex gl-w-full gl-items-center gl-px-5 gl-py-3">
|
|
144
|
+
<h4
|
|
145
|
+
v-if="subtitle"
|
|
146
|
+
class="gl-mb-0 gl-shrink-0 gl-overflow-hidden gl-text-ellipsis gl-whitespace-nowrap gl-pr-3 gl-text-sm gl-font-normal gl-text-subtle"
|
|
147
|
+
data-testid="chat-subtitle"
|
|
148
|
+
>
|
|
149
|
+
{{ subtitle }}
|
|
150
|
+
</h4>
|
|
151
|
+
<gl-button
|
|
152
|
+
category="tertiary"
|
|
153
|
+
variant="default"
|
|
154
|
+
icon="close"
|
|
155
|
+
size="small"
|
|
156
|
+
class="gl-ml-auto"
|
|
157
|
+
data-testid="chat-close-button"
|
|
158
|
+
:aria-label="$options.i18n.CHAT_CLOSE_LABEL"
|
|
159
|
+
@click="$emit('close')"
|
|
160
|
+
/>
|
|
161
|
+
</div>
|
|
143
162
|
<div class="drawer-title gl-flex gl-items-center gl-justify-start gl-p-5">
|
|
144
|
-
<div class="gl-flex-1 gl-overflow-hidden">
|
|
163
|
+
<div class="gl-flex gl-flex-1 gl-overflow-hidden">
|
|
164
|
+
<gl-avatar :size="32" :entity-name="title" shape="circle" class="gl-mr-3" />
|
|
145
165
|
<div class="gl-flex gl-items-center">
|
|
146
|
-
<h3 class="gl-my-0 gl-text-
|
|
147
|
-
<gl-experiment-badge v-if="badgeType" :type="badgeType" container-id="chat-component" />
|
|
166
|
+
<h3 class="gl-my-0 gl-text-[0.875rem]">{{ title }}</h3>
|
|
148
167
|
</div>
|
|
149
|
-
<h4
|
|
150
|
-
v-if="subtitle"
|
|
151
|
-
class="gl-mb-0 gl-overflow-hidden gl-text-ellipsis gl-whitespace-nowrap gl-pr-3 gl-text-sm gl-font-normal gl-text-subtle"
|
|
152
|
-
data-testid="chat-subtitle"
|
|
153
|
-
>
|
|
154
|
-
{{ subtitle }}
|
|
155
|
-
</h4>
|
|
156
168
|
</div>
|
|
157
169
|
|
|
158
170
|
<div class="gl-flex gl-gap-3">
|
|
@@ -242,16 +254,6 @@ export default {
|
|
|
242
254
|
</span>
|
|
243
255
|
</gl-dropdown-item>
|
|
244
256
|
</gl-dropdown>
|
|
245
|
-
<gl-button
|
|
246
|
-
category="tertiary"
|
|
247
|
-
variant="default"
|
|
248
|
-
icon="close"
|
|
249
|
-
size="small"
|
|
250
|
-
class="gl-ml-auto"
|
|
251
|
-
data-testid="chat-close-button"
|
|
252
|
-
:aria-label="$options.i18n.CHAT_CLOSE_LABEL"
|
|
253
|
-
@click="$emit('close')"
|
|
254
|
-
/>
|
|
255
257
|
</div>
|
|
256
258
|
</div>
|
|
257
259
|
|