@gitlab/duo-ui 15.0.2 → 15.0.4

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 CHANGED
@@ -1,3 +1,17 @@
1
+ ## [15.0.4](https://gitlab.com/gitlab-org/duo-ui/compare/v15.0.3...v15.0.4) (2025-12-03)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **DuoChat:** Add vertical centering for custom empty state slot ([922ed40](https://gitlab.com/gitlab-org/duo-ui/commit/922ed404f53c151ea5595e72d8905ecad42c8581))
7
+
8
+ ## [15.0.3](https://gitlab.com/gitlab-org/duo-ui/compare/v15.0.2...v15.0.3) (2025-12-02)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **WebDuoChatHeader:** Break longer titles anywhere to ellipse them ([91e5dca](https://gitlab.com/gitlab-org/duo-ui/commit/91e5dca7e63adb7b30aa3509f4b754dd7a821e0a))
14
+
1
15
  ## [15.0.2](https://gitlab.com/gitlab-org/duo-ui/compare/v15.0.1...v15.0.2) (2025-11-26)
2
16
 
3
17
 
@@ -145,6 +145,25 @@ var script = {
145
145
  required: false,
146
146
  default: ''
147
147
  },
148
+ /**
149
+ * Chat state object that contains enablement state and optional reason message.
150
+ * When chat is disabled (isEnabled: false), a reason message must be provided.
151
+ */
152
+ chatState: {
153
+ type: Object,
154
+ required: false,
155
+ default: () => ({
156
+ isEnabled: true,
157
+ reason: null
158
+ }),
159
+ validator: value => {
160
+ // If chat is disabled, reason must be provided
161
+ if (!value.isEnabled && !value.reason) {
162
+ return false;
163
+ }
164
+ return true;
165
+ }
166
+ },
148
167
  /**
149
168
  * Array of messages to display in the chat.
150
169
  */
@@ -725,7 +744,11 @@ var script = {
725
744
  const __vue_script__ = script;
726
745
 
727
746
  /* template */
728
- var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"markdown-code-block duo-chat web-only gl-bottom-0 gl-flex gl-max-h-full gl-flex-grow gl-flex-col",attrs:{"id":"chat-component","role":"complementary","data-testid":"chat-component"}},[(_vm.showHeader)?_c('web-duo-chat-header',{ref:"header",attrs:{"active-thread-id":_vm.activeThreadId,"title":_vm.isMultithreaded && _vm.currentView === 'list' ? _vm.$options.i18n.CHAT_HISTORY_TITLE : _vm.title,"subtitle":_vm.activeThreadTitleForView,"error":_vm.error,"is-multithreaded":_vm.isMultithreaded,"current-view":_vm.currentView,"should-render-resizable":_vm.shouldRenderResizable,"badge-type":_vm.isMultithreaded ? null : _vm.badgeType,"session-id":_vm.sessionId,"agents":_vm.agents,"show-studio-header":_vm.showStudioHeader},on:{"go-back":_vm.onGoBack,"new-chat":_vm.onNewChat,"close":_vm.hideChat},scopedSlots:_vm._u([{key:"subheader",fn:function(){return [_vm._t("subheader")]},proxy:true}],null,true)}):_vm._e(),_vm._v(" "),_c('div',{staticClass:"gl-flex gl-flex-1 gl-flex-grow gl-flex-col gl-overflow-y-auto gl-overscroll-contain gl-bg-inherit",class:{ 'gl-border-t': !_vm.showStudioHeader },attrs:{"data-testid":"chat-history"},on:{"scroll":_vm.handleScrollingThrottled}},[(_vm.shouldShowThreadList)?_c('duo-chat-threads',{attrs:{"threads":_vm.threadList,"preferred-locale":_vm.preferredLocale},on:{"new-chat":_vm.onNewChat,"select-thread":_vm.onSelectThread,"delete-thread":_vm.onDeleteThread,"close":_vm.hideChat}}):_c('transition-group',{staticClass:"duo-chat-history gl-mt-auto gl-px-4 gl-pb-4 gl-pt-6",attrs:{"mode":"out-in","tag":"section","name":"message"}},[_vm._l((_vm.conversations),function(conversation,index){return _c('duo-chat-conversation',{key:("conversation-" + index),attrs:{"enable-code-insertion":_vm.enableCodeInsertion,"messages":conversation,"show-delimiter":index > 0,"with-feedback":_vm.withFeedback,"is-tool-approval-processing":_vm.isToolApprovalProcessing,"working-directory":_vm.workingDirectory},on:{"track-feedback":_vm.onTrackFeedback,"insert-code-snippet":_vm.onInsertCodeSnippet,"copy-code-snippet":_vm.onCopyCodeSnippet,"copy-message":_vm.onCopyMessage,"get-context-item-content":_vm.onGetContextItemContent,"approve-tool":_vm.onApproveToolCall,"deny-tool":_vm.onDenyToolCall,"open-file-path":_vm.onOpenFilePath}})}),_vm._v(" "),(!_vm.hasMessages && !_vm.isLoading)?[_c('div',{key:"empty-state-message",staticClass:"duo-chat-message gl-rounded-bl-none gl-leading-20 gl-text-default gl-break-anywhere",attrs:{"data-testid":"gl-duo-chat-empty-state"}},[_c('div',{staticClass:"gl-mb-[3.75rem] gl-flex gl-flex-col gl-items-center gl-justify-center gl-gap-3 gl-text-center"},[_c('h1',{staticClass:"gl-my-0 gl-text-[3.5rem]",attrs:{"data-testid":"gl-duo-chat-empty-state-emoji"}},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CHAT_EMPTY_STATE_EMOJI)+"\n ")]),_vm._v(" "),(_vm.agentName)?_c('h2',{staticClass:"gl-heading-2 gl-my-0",attrs:{"data-testid":"gl-duo-chat-empty-state-greeting"}},[_vm._v("\n "+_vm._s(_vm.emptyStateGreeting)+"\n ")]):_vm._e(),_vm._v(" "),_c('h2',{staticClass:"gl-my-0 gl-text-size-h2",attrs:{"data-testid":"gl-duo-chat-empty-state-title"}},[_vm._v("\n "+_vm._s(_vm.emptyStateMainText)+"\n ")]),_vm._v(" "),_c('p',{staticClass:"gl-text-base gl-text-subtle",attrs:{"data-testid":"gl-duo-chat-empty-state-subtitle"}},[_vm._v("\n "+_vm._s(_vm.emptyStateSubText)+"\n ")])]),_vm._v(" "),_c('duo-chat-predefined-prompts',{key:"predefined-prompts",attrs:{"prompts":_vm.predefinedPrompts},on:{"click":_vm.sendPredefinedPrompt}})],1)]:_vm._e(),_vm._v(" "),(_vm.isLoading)?_c('duo-chat-loader',{key:"loader",attrs:{"tool-name":_vm.toolName}}):_vm._e(),_vm._v(" "),_c('div',{key:"anchor",ref:"anchor",staticClass:"scroll-anchor"})],2)],1),_vm._v(" "),(_vm.isChatAvailable && !_vm.shouldShowThreadList)?_c('footer',{staticClass:"duo-chat-drawer-footer gl-relative gl-z-2 gl-shrink-0",attrs:{"data-testid":"chat-footer"}},[_c('p',{staticClass:"gl-mb-3 gl-text-sm gl-text-subtle",class:{ 'gl-invisible': !_vm.hasAssistantMessages },attrs:{"data-testid":"chat-disclaimer"}},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CHAT_DISCLAIMER)+"\n ")]),_vm._v(" "),_c('gl-form',{attrs:{"data-testid":"chat-prompt-form"},on:{"submit":function($event){$event.stopPropagation();$event.preventDefault();return _vm.sendChatPrompt.apply(null, arguments)}}},[_c('div',{staticClass:"gl-relative gl-max-w-full"},[_vm._t("context-items-menu",null,{"isOpen":_vm.contextItemsMenuIsOpen,"onClose":_vm.closeContextItemsMenuOpen,"setRef":_vm.setContextItemsMenuRef,"focusPrompt":_vm.focusChatInput})],2),_vm._v(" "),_c('div',{staticClass:"duo-chat-input gl-relative 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 forced-colors:gl-border"},[(_vm.$scopedSlots['agentic-model'] || _vm.$scopedSlots['agentic-switch'])?_c('div',{staticClass:"gl-flex gl-items-center gl-justify-between gl-gap-5 gl-border-0 gl-border-b-1 gl-border-solid gl-border-strong gl-px-4 gl-py-4 forced-colors:gl-border-none"},[_c('div',{staticClass:"duo-model-switcher gl-min-w-0 gl-max-w-full"},[_vm._t("agentic-model")],2),_vm._v(" "),_c('div',{staticClass:"duo-agent-mode-switcher gl-min-w-0 gl-max-w-full gl-shrink-0"},[_vm._t("agentic-switch")],2)]):_vm._e(),_vm._v(" "),_c('div',{staticClass:"gl-h-[80px] gl-grow",attrs:{"data-value":_vm.prompt}},[(_vm.shouldShowSlashCommands)?_c('gl-card',{ref:"commands",staticClass:"slash-commands !gl-absolute gl-w-full -gl-translate-y-full gl-list-none gl-pl-0 gl-shadow-md",attrs:{"body-class":"!gl-p-2"}},_vm._l((_vm.filteredSlashCommands),function(command,index){return _c('gl-dropdown-item',{key:command.name,class:{ 'active-command': index === _vm.activeCommandIndex },on:{"click":function($event){return _vm.selectSlashCommand(index)}},nativeOn:{"mouseenter":function($event){_vm.activeCommandIndex = index;}}},[_c('span',{staticClass:"gl-flex gl-justify-between"},[_c('span',{staticClass:"gl-block"},[_vm._v(_vm._s(command.name))]),_vm._v(" "),_c('small',{staticClass:"gl-pl-3 gl-text-right gl-italic gl-text-subtle"},[_vm._v(_vm._s(command.description))])])])}),1):_vm._e(),_vm._v(" "),_c('gl-form-textarea',{ref:"prompt",attrs:{"disabled":!_vm.canSubmit,"data-testid":"chat-prompt-input","placeholder":_vm.inputPlaceholder,"character-count-limit":_vm.maxPromptLength,"textarea-classes":[
747
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"markdown-code-block duo-chat web-only gl-bottom-0 gl-flex gl-max-h-full gl-flex-grow gl-flex-col",attrs:{"id":"chat-component","role":"complementary","data-testid":"chat-component"}},[(_vm.showHeader)?_c('web-duo-chat-header',{ref:"header",attrs:{"active-thread-id":_vm.activeThreadId,"title":_vm.isMultithreaded && _vm.currentView === 'list' ? _vm.$options.i18n.CHAT_HISTORY_TITLE : _vm.title,"subtitle":_vm.activeThreadTitleForView,"error":_vm.error,"info":_vm.hasMessages ? _vm.chatState.reason : '',"is-multithreaded":_vm.isMultithreaded,"current-view":_vm.currentView,"should-render-resizable":_vm.shouldRenderResizable,"badge-type":_vm.isMultithreaded ? null : _vm.badgeType,"session-id":_vm.sessionId,"agents":_vm.agents,"show-studio-header":_vm.showStudioHeader},on:{"go-back":_vm.onGoBack,"new-chat":_vm.onNewChat,"close":_vm.hideChat},scopedSlots:_vm._u([{key:"subheader",fn:function(){return [_vm._t("subheader")]},proxy:true}],null,true)}):_vm._e(),_vm._v(" "),_c('div',{staticClass:"gl-flex gl-flex-1 gl-flex-grow gl-flex-col gl-overflow-y-auto gl-overscroll-contain gl-bg-inherit",class:{ 'gl-border-t': !_vm.showStudioHeader },attrs:{"data-testid":"chat-history"},on:{"scroll":_vm.handleScrollingThrottled}},[(_vm.shouldShowThreadList)?_c('duo-chat-threads',{attrs:{"threads":_vm.threadList,"preferred-locale":_vm.preferredLocale},on:{"new-chat":_vm.onNewChat,"select-thread":_vm.onSelectThread,"delete-thread":_vm.onDeleteThread,"close":_vm.hideChat}}):_c('transition-group',{class:[
748
+ 'duo-chat-history gl-px-4',
749
+ _vm.$scopedSlots['custom-empty-state']
750
+ ? 'gl-flex gl-flex-1 gl-items-center gl-justify-center'
751
+ : 'gl-mt-auto gl-pb-4 gl-pt-6' ],attrs:{"mode":"out-in","tag":"section","name":"message","data-testid":"chat-messages"}},[_vm._l((_vm.conversations),function(conversation,index){return _c('duo-chat-conversation',{key:("conversation-" + index),attrs:{"enable-code-insertion":_vm.enableCodeInsertion,"messages":conversation,"show-delimiter":index > 0,"with-feedback":_vm.withFeedback,"is-tool-approval-processing":_vm.isToolApprovalProcessing,"working-directory":_vm.workingDirectory},on:{"track-feedback":_vm.onTrackFeedback,"insert-code-snippet":_vm.onInsertCodeSnippet,"copy-code-snippet":_vm.onCopyCodeSnippet,"copy-message":_vm.onCopyMessage,"get-context-item-content":_vm.onGetContextItemContent,"approve-tool":_vm.onApproveToolCall,"deny-tool":_vm.onDenyToolCall,"open-file-path":_vm.onOpenFilePath}})}),_vm._v(" "),(!_vm.hasMessages && !_vm.isLoading)?[_vm._t("custom-empty-state",function(){return [_c('div',{key:"empty-state-message",staticClass:"duo-chat-message gl-rounded-bl-none gl-leading-20 gl-text-default gl-break-anywhere",attrs:{"data-testid":"gl-duo-chat-empty-state"}},[_c('div',{staticClass:"gl-mb-[3.75rem] gl-flex gl-flex-col gl-items-center gl-justify-center gl-gap-3 gl-text-center"},[_c('h1',{staticClass:"gl-my-0 gl-text-[3.5rem]",attrs:{"data-testid":"gl-duo-chat-empty-state-emoji"}},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CHAT_EMPTY_STATE_EMOJI)+"\n ")]),_vm._v(" "),(_vm.agentName)?_c('h2',{staticClass:"gl-heading-2 gl-my-0",attrs:{"data-testid":"gl-duo-chat-empty-state-greeting"}},[_vm._v("\n "+_vm._s(_vm.emptyStateGreeting)+"\n ")]):_vm._e(),_vm._v(" "),_c('h2',{staticClass:"gl-my-0 gl-text-size-h2",attrs:{"data-testid":"gl-duo-chat-empty-state-title"}},[_vm._v("\n "+_vm._s(_vm.emptyStateMainText)+"\n ")]),_vm._v(" "),_c('p',{staticClass:"gl-text-base gl-text-subtle",attrs:{"data-testid":"gl-duo-chat-empty-state-subtitle"}},[_vm._v("\n "+_vm._s(_vm.emptyStateSubText)+"\n ")])]),_vm._v(" "),_c('duo-chat-predefined-prompts',{key:"predefined-prompts",attrs:{"prompts":_vm.predefinedPrompts},on:{"click":_vm.sendPredefinedPrompt}})],1)]})]:_vm._e(),_vm._v(" "),(_vm.isLoading)?_c('duo-chat-loader',{key:"loader",attrs:{"tool-name":_vm.toolName}}):_vm._e(),_vm._v(" "),_c('div',{key:"anchor",ref:"anchor",staticClass:"scroll-anchor"})],2)],1),_vm._v(" "),(!_vm.shouldShowThreadList)?_c('footer',{staticClass:"duo-chat-drawer-footer gl-relative gl-z-2 gl-shrink-0",attrs:{"data-testid":"chat-footer"}},[_c('p',{staticClass:"gl-mb-3 gl-text-sm gl-text-subtle",class:{ 'gl-invisible': !_vm.hasAssistantMessages },attrs:{"data-testid":"chat-disclaimer"}},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CHAT_DISCLAIMER)+"\n ")]),_vm._v(" "),_c('gl-form',{attrs:{"data-testid":"chat-prompt-form"},on:{"submit":function($event){$event.stopPropagation();$event.preventDefault();return _vm.sendChatPrompt.apply(null, arguments)}}},[_c('div',{staticClass:"gl-relative gl-max-w-full"},[_vm._t("context-items-menu",null,{"isOpen":_vm.contextItemsMenuIsOpen,"onClose":_vm.closeContextItemsMenuOpen,"setRef":_vm.setContextItemsMenuRef,"focusPrompt":_vm.focusChatInput})],2),_vm._v(" "),_c('div',{staticClass:"duo-chat-input gl-relative 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 forced-colors:gl-border"},[(_vm.$scopedSlots['agentic-model'] || _vm.$scopedSlots['agentic-switch'])?_c('div',{staticClass:"gl-flex gl-items-center gl-justify-between gl-gap-5 gl-border-0 gl-border-b-1 gl-border-solid gl-border-strong gl-px-4 gl-py-4 forced-colors:gl-border-none"},[_c('div',{staticClass:"duo-model-switcher gl-min-w-0 gl-max-w-full"},[_vm._t("agentic-model")],2),_vm._v(" "),_c('div',{staticClass:"duo-agent-mode-switcher gl-min-w-0 gl-max-w-full gl-shrink-0"},[_vm._t("agentic-switch")],2)]):_vm._e(),_vm._v(" "),_c('div',{staticClass:"gl-h-[80px] gl-grow",attrs:{"data-value":_vm.prompt}},[(_vm.shouldShowSlashCommands)?_c('gl-card',{ref:"commands",staticClass:"slash-commands !gl-absolute gl-w-full -gl-translate-y-full gl-list-none gl-pl-0 gl-shadow-md",attrs:{"body-class":"!gl-p-2"}},_vm._l((_vm.filteredSlashCommands),function(command,index){return _c('gl-dropdown-item',{key:command.name,class:{ 'active-command': index === _vm.activeCommandIndex },on:{"click":function($event){return _vm.selectSlashCommand(index)}},nativeOn:{"mouseenter":function($event){_vm.activeCommandIndex = index;}}},[_c('span',{staticClass:"gl-flex gl-justify-between"},[_c('span',{staticClass:"gl-block"},[_vm._v(_vm._s(command.name))]),_vm._v(" "),_c('small',{staticClass:"gl-pl-3 gl-text-right gl-italic gl-text-subtle"},[_vm._v(_vm._s(command.description))])])])}),1):_vm._e(),_vm._v(" "),_c('gl-form-textarea',{ref:"prompt",attrs:{"disabled":!_vm.canSubmit || !_vm.isChatAvailable || !_vm.chatState.isEnabled,"data-testid":"chat-prompt-input","placeholder":_vm.inputPlaceholder,"character-count-limit":_vm.maxPromptLength,"textarea-classes":[
729
752
  '!gl-h-full',
730
753
  '!gl-bg-transparent',
731
754
  '!gl-py-4',
@@ -747,7 +770,7 @@ return [(count <= _vm.promptLengthWarningCount)?_c('span',{staticClass:"gl-absol
747
770
  return [_c('span',{staticClass:"gl-absolute gl-bottom-[-1.6rem] gl-right-0 gl-mt-3 gl-pr-3 gl-text-sm",class:{
748
771
  'gl-bottom-[-5rem]': _vm.hasFooterControls,
749
772
  'gl-bottom-[-1.6rem]': !_vm.hasFooterControls,
750
- }},[_vm._v(_vm._s(_vm.overLimitCharacterCountMessage(count)))])]}}],null,false,4237892236),model:{value:(_vm.prompt),callback:function ($$v) {_vm.prompt=$$v;},expression:"prompt"}})],1),_vm._v(" "),_c('div',{staticClass:"gl-absolute gl-bottom-0 gl-right-0 gl-px-3 gl-pb-3"},[(_vm.canSubmit)?_c('gl-button',{staticClass:"!gl-rounded-full",attrs:{"icon":"paper-airplane","category":"primary","variant":"confirm","type":"submit","disabled":_vm.isPromptEmpty || !_vm.hasValidPrompt,"data-testid":"chat-prompt-submit-button","aria-label":_vm.$options.i18n.CHAT_SUBMIT_LABEL}}):_c('gl-button',{staticClass:"!gl-rounded-full",attrs:{"icon":"stop","category":"primary","variant":"default","data-testid":"chat-prompt-cancel-button","aria-label":_vm.$options.i18n.CHAT_CANCEL_LABEL},on:{"click":_vm.cancelPrompt}})],1)])]),_vm._v(" "),_vm._t("footer-controls")],2):_vm._e()],1)};
773
+ }},[_vm._v(_vm._s(_vm.overLimitCharacterCountMessage(count)))])]}}],null,false,4237892236),model:{value:(_vm.prompt),callback:function ($$v) {_vm.prompt=$$v;},expression:"prompt"}})],1),_vm._v(" "),_c('div',{staticClass:"gl-absolute gl-bottom-0 gl-right-0 gl-px-3 gl-pb-3"},[(_vm.canSubmit)?_c('gl-button',{staticClass:"!gl-rounded-full",attrs:{"icon":"paper-airplane","category":"primary","variant":"confirm","type":"submit","disabled":!_vm.isChatAvailable || !_vm.chatState.isEnabled || _vm.isPromptEmpty || !_vm.hasValidPrompt,"data-testid":"chat-prompt-submit-button","aria-label":_vm.$options.i18n.CHAT_SUBMIT_LABEL}}):_c('gl-button',{staticClass:"!gl-rounded-full",attrs:{"icon":"stop","category":"primary","variant":"default","data-testid":"chat-prompt-cancel-button","aria-label":_vm.$options.i18n.CHAT_CANCEL_LABEL},on:{"click":_vm.cancelPrompt}})],1)])]),_vm._v(" "),_vm._t("footer-controls")],2):_vm._e()],1)};
751
774
  var __vue_staticRenderFns__ = [];
752
775
 
753
776
  /* style */
@@ -53,6 +53,11 @@ var script = {
53
53
  required: false,
54
54
  default: ''
55
55
  },
56
+ info: {
57
+ type: String,
58
+ required: false,
59
+ default: ''
60
+ },
56
61
  isMultithreaded: {
57
62
  type: Boolean,
58
63
  required: false,
@@ -155,7 +160,7 @@ var script = {
155
160
  const __vue_script__ = script;
156
161
 
157
162
  /* template */
158
- var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('header',{staticClass:"gl-shrink-0 gl-p-0",attrs:{"data-testid":"chat-header"}},[(!_vm.showStudioHeader)?_c('div',{staticClass:"gl-flex gl-w-full gl-items-center gl-px-4 gl-py-3",attrs:{"data-testid":"chat-top-header"}},[(_vm.subtitle)?_c('h4',{staticClass:"gl-mb-0 gl-max-w-17/20 gl-flex-1 gl-shrink-0 gl-overflow-hidden gl-truncate gl-text-ellipsis gl-whitespace-nowrap gl-pr-3 gl-text-sm gl-font-normal gl-text-subtle",attrs:{"data-testid":"chat-subtitle"}},[_vm._v("\n "+_vm._s(_vm.subtitle)+"\n ")]):_vm._e(),_vm._v(" "),_c('div',{staticClass:"gl-ml-auto gl-flex gl-gap-3"},[(_vm.sessionId)?_c('gl-disclosure-dropdown',{directives:[{name:"gl-tooltip",rawName:"v-gl-tooltip",value:(_vm.showSessionDropdownTooltip),expression:"showSessionDropdownTooltip"}],attrs:{"icon":"ellipsis_v","category":"tertiary","text-sr-only":"","size":"small","toggle-text":_vm.$options.i18n.CHAT_DROPDOWN_MORE_OPTIONS,"items":_vm.sessionIdItems,"no-caret":""},on:{"shown":_vm.showSessionDropdown,"hidden":_vm.hideSessionDropdown}}):_vm._e(),_vm._v(" "),_c('gl-button',{attrs:{"category":"tertiary","variant":"default","icon":"close","size":"small","data-testid":"chat-close-button","aria-label":_vm.$options.i18n.CHAT_CLOSE_LABEL},on:{"click":function($event){return _vm.$emit('close')}}})],1)]):_vm._e(),_vm._v(" "),(_vm.showSubheader)?_c('div',{staticClass:"drawer-title gl-flex gl-items-center gl-justify-start gl-gap-4 gl-px-4 gl-py-3",class:{ 'gl-border-t': !_vm.showStudioHeader, 'gl-border-b': _vm.showStudioHeader },attrs:{"data-testid":"chat-subheader"}},[_c('div',{staticClass:"gl-flex gl-grow gl-gap-3"},[_c('gl-avatar',{staticClass:"gl-shrink-0",attrs:{"size":32,"entity-name":_vm.title,"shape":"circle"}}),_vm._v(" "),_c('div',{staticClass:"gl-flex gl-flex-col gl-justify-center"},[_c('h3',{staticClass:"gl-my-0 gl-line-clamp-1 gl-text-[0.875rem] gl-text-default"},[_vm._v(_vm._s(_vm.title))]),_vm._v(" "),(_vm.agentHandler)?_c('p',{staticClass:"gl-my-0 gl-text-[0.75rem] gl-text-subtle"},[_vm._v("\n "+_vm._s(_vm.agentHandler)+"\n ")]):_vm._e()])],1),_vm._v(" "),_c('div',{staticClass:"gl-flex gl-gap-3"},[(_vm.isMultithreaded && _vm.activeThreadId && _vm.currentView === _vm.VIEW_TYPES.LIST)?_c('gl-button',{directives:[{name:"gl-tooltip",rawName:"v-gl-tooltip"}],attrs:{"title":_vm.$options.i18n.CHAT_BACK_TO_CHAT_TOOLTIP,"data-testid":"go-back-to-chat-button","category":"tertiary","size":"small","icon":"go-back","aria-label":_vm.$options.i18n.CHAT_BACK_TO_CHAT_TOOLTIP},on:{"click":function($event){return _vm.$emit('go-back-to-chat')}}}):_vm._e()],1)]):_vm._e(),_vm._v(" "),_vm._t("subheader"),_vm._v(" "),(_vm.error)?_c('gl-alert',{key:"error",staticClass:"!gl-pl-9",attrs:{"dismissible":false,"variant":"danger","role":"alert","data-testid":"chat-error"}},[_c('span',{directives:[{name:"safe-html",rawName:"v-safe-html",value:(_vm.error),expression:"error"}]})]):_vm._e()],2)};
163
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('header',{staticClass:"gl-shrink-0 gl-p-0",attrs:{"data-testid":"chat-header"}},[(!_vm.showStudioHeader)?_c('div',{staticClass:"gl-flex gl-w-full gl-items-center gl-px-4 gl-py-3",attrs:{"data-testid":"chat-top-header"}},[(_vm.subtitle)?_c('h4',{staticClass:"gl-mb-0 gl-max-w-17/20 gl-flex-1 gl-shrink-0 gl-overflow-hidden gl-truncate gl-text-ellipsis gl-whitespace-nowrap gl-pr-3 gl-text-sm gl-font-normal gl-text-subtle",attrs:{"data-testid":"chat-subtitle"}},[_vm._v("\n "+_vm._s(_vm.subtitle)+"\n ")]):_vm._e(),_vm._v(" "),_c('div',{staticClass:"gl-ml-auto gl-flex gl-gap-3"},[(_vm.sessionId)?_c('gl-disclosure-dropdown',{directives:[{name:"gl-tooltip",rawName:"v-gl-tooltip",value:(_vm.showSessionDropdownTooltip),expression:"showSessionDropdownTooltip"}],attrs:{"icon":"ellipsis_v","category":"tertiary","text-sr-only":"","size":"small","toggle-text":_vm.$options.i18n.CHAT_DROPDOWN_MORE_OPTIONS,"items":_vm.sessionIdItems,"no-caret":""},on:{"shown":_vm.showSessionDropdown,"hidden":_vm.hideSessionDropdown}}):_vm._e(),_vm._v(" "),_c('gl-button',{attrs:{"category":"tertiary","variant":"default","icon":"close","size":"small","data-testid":"chat-close-button","aria-label":_vm.$options.i18n.CHAT_CLOSE_LABEL},on:{"click":function($event){return _vm.$emit('close')}}})],1)]):_vm._e(),_vm._v(" "),(_vm.showSubheader)?_c('div',{staticClass:"drawer-title gl-flex gl-items-center gl-justify-start gl-gap-4 gl-px-4 gl-py-3",class:{ 'gl-border-t': !_vm.showStudioHeader, 'gl-border-b': _vm.showStudioHeader },attrs:{"data-testid":"chat-subheader"}},[_c('div',{staticClass:"gl-flex gl-grow gl-gap-3"},[_c('gl-avatar',{staticClass:"gl-shrink-0",attrs:{"size":32,"entity-name":_vm.title,"shape":"circle"}}),_vm._v(" "),_c('div',{staticClass:"gl-flex gl-flex-col gl-justify-center"},[_c('h3',{staticClass:"gl-my-0 gl-line-clamp-1 gl-text-[0.875rem] gl-text-default gl-break-anywhere"},[_vm._v("\n "+_vm._s(_vm.title)+"\n ")]),_vm._v(" "),(_vm.agentHandler)?_c('p',{staticClass:"gl-my-0 gl-text-[0.75rem] gl-text-subtle"},[_vm._v("\n "+_vm._s(_vm.agentHandler)+"\n ")]):_vm._e()])],1),_vm._v(" "),_c('div',{staticClass:"gl-flex gl-gap-3"},[(_vm.isMultithreaded && _vm.activeThreadId && _vm.currentView === _vm.VIEW_TYPES.LIST)?_c('gl-button',{directives:[{name:"gl-tooltip",rawName:"v-gl-tooltip"}],attrs:{"title":_vm.$options.i18n.CHAT_BACK_TO_CHAT_TOOLTIP,"data-testid":"go-back-to-chat-button","category":"tertiary","size":"small","icon":"go-back","aria-label":_vm.$options.i18n.CHAT_BACK_TO_CHAT_TOOLTIP},on:{"click":function($event){return _vm.$emit('go-back-to-chat')}}}):_vm._e()],1)]):_vm._e(),_vm._v(" "),_vm._t("subheader"),_vm._v(" "),(_vm.info)?_c('gl-alert',{key:"info",staticClass:"!gl-pl-9",attrs:{"dismissible":false,"variant":"info","role":"alert","data-testid":"chat-info"}},[_c('span',{directives:[{name:"safe-html",rawName:"v-safe-html",value:(_vm.info),expression:"info"}]})]):_vm._e(),_vm._v(" "),(_vm.error)?_c('gl-alert',{key:"error",staticClass:"!gl-pl-9",attrs:{"dismissible":false,"variant":"danger","role":"alert","data-testid":"chat-error"}},[_c('span',{directives:[{name:"safe-html",rawName:"v-safe-html",value:(_vm.error),expression:"error"}]})]):_vm._e()],2)};
159
164
  var __vue_staticRenderFns__ = [];
160
165
 
161
166
  /* style */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/duo-ui",
3
- "version": "15.0.2",
3
+ "version": "15.0.4",
4
4
  "description": "Duo UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -159,8 +159,8 @@
159
159
  "module-alias": "^2.2.2",
160
160
  "npm-run-all": "^4.1.5",
161
161
  "pikaday": "^1.8.0",
162
- "playwright": "^1.56.1",
163
- "playwright-core": "^1.56.1",
162
+ "playwright": "^1.57.0",
163
+ "playwright-core": "^1.57.0",
164
164
  "plop": "^2.5.4",
165
165
  "postcss": "8.4.28",
166
166
  "postcss-loader": "^7.0.2",
@@ -210,6 +210,22 @@ export default {
210
210
  required: false,
211
211
  default: '',
212
212
  },
213
+ /**
214
+ * Chat state object that contains enablement state and optional reason message.
215
+ * When chat is disabled (isEnabled: false), a reason message must be provided.
216
+ */
217
+ chatState: {
218
+ type: Object,
219
+ required: false,
220
+ default: () => ({ isEnabled: true, reason: null }),
221
+ validator: (value) => {
222
+ // If chat is disabled, reason must be provided
223
+ if (!value.isEnabled && !value.reason) {
224
+ return false;
225
+ }
226
+ return true;
227
+ },
228
+ },
213
229
  /**
214
230
  * Array of messages to display in the chat.
215
231
  */
@@ -824,6 +840,7 @@ export default {
824
840
  :title="isMultithreaded && currentView === 'list' ? $options.i18n.CHAT_HISTORY_TITLE : title"
825
841
  :subtitle="activeThreadTitleForView"
826
842
  :error="error"
843
+ :info="hasMessages ? chatState.reason : ''"
827
844
  :is-multithreaded="isMultithreaded"
828
845
  :current-view="currentView"
829
846
  :should-render-resizable="shouldRenderResizable"
@@ -860,7 +877,13 @@ export default {
860
877
  mode="out-in"
861
878
  tag="section"
862
879
  name="message"
863
- class="duo-chat-history gl-mt-auto gl-px-4 gl-pb-4 gl-pt-6"
880
+ data-testid="chat-messages"
881
+ :class="[
882
+ 'duo-chat-history gl-px-4',
883
+ $scopedSlots['custom-empty-state']
884
+ ? 'gl-flex gl-flex-1 gl-items-center gl-justify-center'
885
+ : 'gl-mt-auto gl-pb-4 gl-pt-6',
886
+ ]"
864
887
  >
865
888
  <duo-chat-conversation
866
889
  v-for="(conversation, index) in conversations"
@@ -881,44 +904,49 @@ export default {
881
904
  @open-file-path="onOpenFilePath"
882
905
  />
883
906
  <template v-if="!hasMessages && !isLoading">
884
- <div
885
- key="empty-state-message"
886
- class="duo-chat-message gl-rounded-bl-none gl-leading-20 gl-text-default gl-break-anywhere"
887
- data-testid="gl-duo-chat-empty-state"
888
- >
907
+ <slot name="custom-empty-state">
889
908
  <div
890
- class="gl-mb-[3.75rem] gl-flex gl-flex-col gl-items-center gl-justify-center gl-gap-3 gl-text-center"
909
+ key="empty-state-message"
910
+ class="duo-chat-message gl-rounded-bl-none gl-leading-20 gl-text-default gl-break-anywhere"
911
+ data-testid="gl-duo-chat-empty-state"
891
912
  >
892
- <h1 class="gl-my-0 gl-text-[3.5rem]" data-testid="gl-duo-chat-empty-state-emoji">
893
- {{ $options.i18n.CHAT_EMPTY_STATE_EMOJI }}
894
- </h1>
895
- <h2
896
- v-if="agentName"
897
- class="gl-heading-2 gl-my-0"
898
- data-testid="gl-duo-chat-empty-state-greeting"
913
+ <div
914
+ class="gl-mb-[3.75rem] gl-flex gl-flex-col gl-items-center gl-justify-center gl-gap-3 gl-text-center"
899
915
  >
900
- {{ emptyStateGreeting }}
901
- </h2>
902
- <h2 class="gl-my-0 gl-text-size-h2" data-testid="gl-duo-chat-empty-state-title">
903
- {{ emptyStateMainText }}
904
- </h2>
905
- <p class="gl-text-base gl-text-subtle" data-testid="gl-duo-chat-empty-state-subtitle">
906
- {{ emptyStateSubText }}
907
- </p>
916
+ <h1 class="gl-my-0 gl-text-[3.5rem]" data-testid="gl-duo-chat-empty-state-emoji">
917
+ {{ $options.i18n.CHAT_EMPTY_STATE_EMOJI }}
918
+ </h1>
919
+ <h2
920
+ v-if="agentName"
921
+ class="gl-heading-2 gl-my-0"
922
+ data-testid="gl-duo-chat-empty-state-greeting"
923
+ >
924
+ {{ emptyStateGreeting }}
925
+ </h2>
926
+ <h2 class="gl-my-0 gl-text-size-h2" data-testid="gl-duo-chat-empty-state-title">
927
+ {{ emptyStateMainText }}
928
+ </h2>
929
+ <p
930
+ class="gl-text-base gl-text-subtle"
931
+ data-testid="gl-duo-chat-empty-state-subtitle"
932
+ >
933
+ {{ emptyStateSubText }}
934
+ </p>
935
+ </div>
936
+ <duo-chat-predefined-prompts
937
+ key="predefined-prompts"
938
+ :prompts="predefinedPrompts"
939
+ @click="sendPredefinedPrompt"
940
+ />
908
941
  </div>
909
- <duo-chat-predefined-prompts
910
- key="predefined-prompts"
911
- :prompts="predefinedPrompts"
912
- @click="sendPredefinedPrompt"
913
- />
914
- </div>
942
+ </slot>
915
943
  </template>
916
944
  <duo-chat-loader v-if="isLoading" key="loader" :tool-name="toolName" />
917
945
  <div key="anchor" ref="anchor" class="scroll-anchor"></div>
918
946
  </transition-group>
919
947
  </div>
920
948
  <footer
921
- v-if="isChatAvailable && !shouldShowThreadList"
949
+ v-if="!shouldShowThreadList"
922
950
  data-testid="chat-footer"
923
951
  class="duo-chat-drawer-footer gl-relative gl-z-2 gl-shrink-0"
924
952
  >
@@ -983,7 +1011,7 @@ export default {
983
1011
  <gl-form-textarea
984
1012
  ref="prompt"
985
1013
  v-model="prompt"
986
- :disabled="!canSubmit"
1014
+ :disabled="!canSubmit || !isChatAvailable || !chatState.isEnabled"
987
1015
  data-testid="chat-prompt-input"
988
1016
  :placeholder="inputPlaceholder"
989
1017
  :character-count-limit="maxPromptLength"
@@ -1045,7 +1073,9 @@ export default {
1045
1073
  variant="confirm"
1046
1074
  class="!gl-rounded-full"
1047
1075
  type="submit"
1048
- :disabled="isPromptEmpty || !hasValidPrompt"
1076
+ :disabled="
1077
+ !isChatAvailable || !chatState.isEnabled || isPromptEmpty || !hasValidPrompt
1078
+ "
1049
1079
  data-testid="chat-prompt-submit-button"
1050
1080
  :aria-label="$options.i18n.CHAT_SUBMIT_LABEL"
1051
1081
  />
@@ -70,6 +70,11 @@ export default {
70
70
  required: false,
71
71
  default: '',
72
72
  },
73
+ info: {
74
+ type: String,
75
+ required: false,
76
+ default: '',
77
+ },
73
78
  isMultithreaded: {
74
79
  type: Boolean,
75
80
  required: false,
@@ -218,7 +223,9 @@ export default {
218
223
  <div class="gl-flex gl-grow gl-gap-3">
219
224
  <gl-avatar :size="32" :entity-name="title" shape="circle" class="gl-shrink-0" />
220
225
  <div class="gl-flex gl-flex-col gl-justify-center">
221
- <h3 class="gl-my-0 gl-line-clamp-1 gl-text-[0.875rem] gl-text-default">{{ title }}</h3>
226
+ <h3 class="gl-my-0 gl-line-clamp-1 gl-text-[0.875rem] gl-text-default gl-break-anywhere">
227
+ {{ title }}
228
+ </h3>
222
229
  <p v-if="agentHandler" class="gl-my-0 gl-text-[0.75rem] gl-text-subtle">
223
230
  {{ agentHandler }}
224
231
  </p>
@@ -242,6 +249,18 @@ export default {
242
249
 
243
250
  <slot name="subheader"></slot>
244
251
 
252
+ <gl-alert
253
+ v-if="info"
254
+ key="info"
255
+ :dismissible="false"
256
+ variant="info"
257
+ class="!gl-pl-9"
258
+ role="alert"
259
+ data-testid="chat-info"
260
+ >
261
+ <span v-safe-html="info"></span>
262
+ </gl-alert>
263
+
245
264
  <gl-alert
246
265
  v-if="error"
247
266
  key="error"