@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.
@@ -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
- "Let's work through this together..."
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?.querySelector?.('textarea')?.focus();
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
- <div
682
- id="chat-component"
683
- class="markdown-code-block duo-chat gl-bottom-0 gl-flex gl-max-h-full gl-flex-col"
684
- role="complementary"
685
- data-testid="chat-component"
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
- <duo-chat-header
688
- v-if="showHeader"
689
- ref="header"
690
- :active-thread-id="activeThreadId"
691
- :title="isMultithreaded && currentView === 'list' ? $options.i18n.CHAT_HISTORY_TITLE : title"
692
- :subtitle="activeThreadTitleForView"
693
- :is-multithreaded="isMultithreaded"
694
- :current-view="currentView"
695
- :should-render-resizable="shouldRenderResizable"
696
- :badge-type="isMultithreaded ? null : badgeType"
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-threads
713
- v-if="shouldShowThreadList"
714
- :threads="threadList"
715
- :preferred-locale="preferredLocale"
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
- <duo-chat-conversation
729
- v-for="(conversation, index) in conversations"
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
- <duo-chat-loader v-if="isLoading" key="loader" :tool-name="toolName" />
760
- <div key="anchor" ref="anchor" class="scroll-anchor"></div>
761
- </transition-group>
762
- </div>
763
- <footer
764
- v-if="isChatAvailable && !shouldShowThreadList"
765
- data-testid="chat-footer"
766
- class="duo-chat-drawer-footer gl-relative gl-z-2 gl-shrink-0 gl-border-0 gl-bg-default gl-pb-3"
767
- :class="{ 'duo-chat-drawer-body-scrim-on-footer': !scrolledToBottom }"
768
- >
769
- <gl-form data-testid="chat-prompt-form" @submit.stop.prevent="sendChatPrompt">
770
- <div class="gl-relative gl-max-w-full">
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
- <slot
775
- name="context-items-menu"
776
- :is-open="contextItemsMenuIsOpen"
777
- :on-close="closeContextItemsMenuOpen"
778
- :set-ref="setContextItemsMenuRef"
779
- :focus-prompt="focusChatInput"
780
- ></slot>
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
- <div class="gl-h-[40px] gl-grow" :data-value="prompt">
793
- <gl-card
794
- v-if="shouldShowSlashCommands"
795
- ref="commands"
796
- class="slash-commands !gl-absolute gl-w-full -gl-translate-y-full gl-list-none gl-pl-0 gl-shadow-md"
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-dropdown-item
800
- v-for="(command, index) in filteredSlashCommands"
801
- :key="command.name"
802
- :class="{ 'active-command': index === activeCommandIndex }"
803
- @mouseenter.native="activeCommandIndex = index"
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
- <span class="gl-flex gl-justify-between">
807
- <span class="gl-block">{{ command.name }}</span>
808
- <small class="gl-pl-3 gl-text-right gl-italic gl-text-subtle">{{
809
- command.description
810
- }}</small>
811
- </span>
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
- {{ remainingCharacterCountMessage(count) }}
848
- </span>
849
- </template>
850
- <template #character-count-over-limit-text="{ count }">
851
- <span class="gl-absolute gl-bottom-[-25px] gl-right-px gl-pr-3">{{
852
- overLimitCharacterCountMessage(count)
853
- }}</span>
854
- </template>
855
- </gl-form-textarea>
856
- </div>
857
- <div class="gl-flex gl-justify-end gl-px-3 gl-pb-3">
858
- <gl-button
859
- v-if="displaySubmitButton"
860
- icon="paper-airplane"
861
- category="primary"
862
- variant="confirm"
863
- class="gl-bottom-2 gl-right-2 gl-ml-auto !gl-rounded-full"
864
- type="submit"
865
- data-testid="chat-prompt-submit-button"
866
- :disabled="isPromptEmpty"
867
- :aria-label="$options.i18n.CHAT_SUBMIT_LABEL"
868
- />
869
- <gl-button
870
- v-else
871
- icon="stop"
872
- category="primary"
873
- variant="default"
874
- class="gl-bottom-2 gl-right-2 gl-ml-auto !gl-rounded-full"
875
- data-testid="chat-prompt-cancel-button"
876
- :aria-label="$options.i18n.CHAT_CANCEL_LABEL"
877
- @click="cancelPrompt"
878
- />
879
- </div>
880
- </div>
881
- </gl-form>
882
- <slot name="footer-controls"></slot>
883
- <p class="gl-mb-0 gl-mt-3 gl-px-4 gl-text-sm gl-text-secondary">
884
- {{ $options.i18n.CHAT_DISCLAMER }}
885
- </p>
886
- </footer>
887
- </div>
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': 'Responses may be inaccurate. Verify before use.',
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.chatModelPlaceholder': 'GitLab Duo Agentic Chat',
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': "Let's work through this together...",
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',