22import { LitElement , html } from 'lit' ;
33import DOMPurify from 'dompurify' ;
44import { customElement , property , query , state } from 'lit/decorators.js' ;
5- import { unsafeHTML } from 'lit/directives/unsafe-html.js' ;
65import { chatHttpOptions , globalConfig , requestOptions , MAX_CHAT_HISTORY } from '../config/global-config.js' ;
76import { chatStyle } from '../styles/chat-component.js' ;
87import { unsafeSVG } from 'lit/directives/unsafe-svg.js' ;
98import { chatEntryToString , newListWithEntryAtIndex } from '../utils/index.js' ;
109
1110// TODO: allow host applications to customize these icons
1211
13- import iconLightBulb from '../../public/svg/lightbulb-icon.svg?raw' ;
1412import iconDelete from '../../public/svg/delete-icon.svg?raw' ;
1513import iconCancel from '../../public/svg/cancel-icon.svg?raw' ;
1614import iconSend from '../../public/svg/send-icon.svg?raw' ;
17- import iconClose from '../../public/svg/close-icon.svg?raw' ;
1815import iconLogo from '../../public/branding/brand-logo.svg?raw' ;
1916import iconUp from '../../public/svg/chevron-up-icon.svg?raw' ;
2017
21- import { type TabContent } from './tab-component.js' ;
2218import { ChatController } from './chat-controller.js' ;
2319import { ChatHistoryController } from './chat-history-controller.js' ;
2420import {
2521 lazyMultiInject ,
2622 ControllerType ,
2723 type ChatInputController ,
2824 type ChatInputFooterController ,
29- type CitationController ,
3025 type ChatSectionController ,
3126} from './composable.js' ;
3227import { ChatContextController } from './chat-context.js' ;
@@ -111,14 +106,6 @@ export class ChatComponent extends LitElement {
111106 @state ( )
112107 isShowingThoughtProcess = false ;
113108
114- @state ( )
115- selectedCitation : Citation | undefined = undefined ;
116-
117- @state ( )
118- selectedChatEntry : ChatThreadEntry | undefined = undefined ;
119-
120- selectedAsideTab : 'tab-thought-process' | 'tab-support-context' | 'tab-citations' = 'tab-thought-process' ;
121-
122109 // These are the chat bubbles that will be displayed in the chat
123110 chatThread : ChatThreadEntry [ ] = [ ] ;
124111
@@ -130,11 +117,8 @@ export class ChatComponent extends LitElement {
130117 @lazyMultiInject ( ControllerType . ChatInputFooter )
131118 chatInputFooterComponets : ChatInputFooterController [ ] | undefined ;
132119
133- @lazyMultiInject ( ControllerType . Citation )
134- citationControllers : CitationController [ ] | undefined ;
135-
136120 @lazyMultiInject ( ControllerType . ChatSection )
137- chatFooterComponents : ChatSectionController [ ] | undefined ;
121+ chatSectionControllers : ChatSectionController [ ] | undefined ;
138122
139123 // Lifecycle method that runs when the component is first connected to the DOM
140124 override connectedCallback ( ) : void {
@@ -149,13 +133,8 @@ export class ChatComponent extends LitElement {
149133 component . attach ( this , this . chatContext ) ;
150134 }
151135 }
152- if ( this . citationControllers ) {
153- for ( const component of this . citationControllers ) {
154- component . attach ( this , this . chatContext ) ;
155- }
156- }
157- if ( this . chatFooterComponents ) {
158- for ( const component of this . chatFooterComponents ) {
136+ if ( this . chatSectionControllers ) {
137+ for ( const component of this . chatSectionControllers ) {
159138 component . attach ( this , this . chatContext ) ;
160139 }
161140 }
@@ -193,15 +172,9 @@ export class ChatComponent extends LitElement {
193172
194173 handleCitationClick ( event : CustomEvent ) : void {
195174 event ?. preventDefault ( ) ;
196- this . selectedCitation = event ?. detail ?. citation ;
197-
198- if ( ! this . isShowingThoughtProcess ) {
199- if ( event ?. detail ?. chatThreadEntry ) {
200- this . selectedChatEntry = event ?. detail ?. chatThreadEntry ;
201- }
202- this . handleExpandAside ( ) ;
203- this . selectedAsideTab = 'tab-citations' ;
204- }
175+ this . chatContext . selectedCitation = event ?. detail ?. citation ;
176+ this . chatContext . selectedChatEntry = event ?. detail ?. chatThreadEntry ;
177+ this . chatContext . setState ( 'showCitations' , true ) ;
205178 }
206179
207180 getMessageContext ( ) : Message [ ] {
@@ -274,7 +247,7 @@ export class ChatComponent extends LitElement {
274247 this . isChatStarted = false ;
275248 this . chatThread = [ ] ;
276249 this . isDisabled = false ;
277- this . selectedCitation = undefined ;
250+ this . chatContext . selectedCitation = undefined ;
278251 this . chatController . reset ( ) ;
279252 // clean up the current session content from the history too
280253 this . chatHistoryController . saveChatHistory ( this . chatThread ) ;
@@ -293,22 +266,14 @@ export class ChatComponent extends LitElement {
293266 this . chatController . cancelRequest ( ) ;
294267 }
295268
296- // show thought process aside
297- handleExpandAside ( event : Event | undefined = undefined ) : void {
298- event ?. preventDefault ( ) ;
299- this . isShowingThoughtProcess = true ;
300- this . selectedAsideTab = 'tab-thought-process' ;
301- this . shadowRoot ?. querySelector ( '#overlay' ) ?. classList . add ( 'active' ) ;
302- this . shadowRoot ?. querySelector ( '#chat__containerWrapper' ) ?. classList . add ( 'aside-open' ) ;
303- }
304-
305269 // hide thought process aside
306270 collapseAside ( event : Event ) : void {
307- event . preventDefault ( ) ;
308- this . isShowingThoughtProcess = false ;
309- this . selectedCitation = undefined ;
310- this . shadowRoot ?. querySelector ( '#chat__containerWrapper' ) ?. classList . remove ( 'aside-open' ) ;
311- this . shadowRoot ?. querySelector ( '#overlay' ) ?. classList . remove ( 'active' ) ;
271+ event ?. preventDefault ( ) ;
272+ if ( this . chatSectionControllers ) {
273+ for ( const component of this . chatSectionControllers ) {
274+ component . close ( ) ;
275+ }
276+ }
312277 }
313278
314279 renderChatOrCancelButton ( ) {
@@ -333,64 +298,6 @@ export class ChatComponent extends LitElement {
333298 return this . chatController . isProcessingResponse ? cancelChatButton : submitChatButton ;
334299 }
335300
336- renderChatEntryTabContent ( entry : ChatThreadEntry ) {
337- return html ` < tab-component
338- .tabs ="${ [
339- {
340- id : 'tab-thought-process' ,
341- label : globalConfig . THOUGHT_PROCESS_LABEL ,
342- } ,
343- {
344- id : 'tab-support-context' ,
345- label : globalConfig . SUPPORT_CONTEXT_LABEL ,
346- } ,
347- {
348- id : 'tab-citations' ,
349- label : globalConfig . CITATIONS_TAB_LABEL ,
350- } ,
351- ] as TabContent [ ] } "
352- .selectedTabId ="${ this . selectedAsideTab } "
353- >
354- < div slot ="tab-thought-process " class ="tab-component__content ">
355- ${ entry && entry . thoughts ? html ` < p class ="tab-component__paragraph "> ${ unsafeHTML ( entry . thoughts ) } </ p > ` : '' }
356- </ div >
357- < div slot ="tab-support-context " class ="tab-component__content ">
358- ${ entry && entry . dataPoints
359- ? html ` < teaser-list-component
360- .alwaysRow ="${ true } "
361- .teasers ="${ entry . dataPoints . map ( ( d ) => {
362- return { description : d } ;
363- } ) } "
364- > </ teaser-list-component > `
365- : '' }
366- </ div >
367- ${ entry && entry . citations
368- ? html `
369- < div slot ="tab-citations " class ="tab-component__content ">
370- < citation-list
371- .citations ="${ entry . citations } "
372- .label ="${ globalConfig . CITATIONS_LABEL } "
373- .selectedCitation ="${ this . selectedCitation } "
374- @on-citation-click ="${ this . handleCitationClick } "
375- > </ citation-list >
376- ${ this . selectedCitation
377- ? this . citationControllers ?. map ( ( component ) =>
378- component . render ( this . selectedCitation , `${ this . apiUrl } /content/${ this . selectedCitation . text } ` ) ,
379- )
380- : '' }
381- </ div >
382- `
383- : '' }
384- </ tab-component > ` ;
385- }
386-
387- handleChatEntryActionButtonClick ( event : CustomEvent ) {
388- if ( event . detail ?. id === 'chat-show-thought-process' ) {
389- this . selectedChatEntry = event . detail ?. chatThreadEntry ;
390- this . handleExpandAside ( event ) ;
391- }
392- }
393-
394301 override willUpdate ( ) : void {
395302 this . isDisabled = this . chatController . generatingAnswer ;
396303
@@ -408,21 +315,12 @@ export class ChatComponent extends LitElement {
408315 renderChatThread ( chatThread : ChatThreadEntry [ ] ) {
409316 return html `< chat-thread-component
410317 .chatThread ="${ chatThread } "
411- .actionButtons ="${ [
412- {
413- id : 'chat-show-thought-process' ,
414- label : globalConfig . SHOW_THOUGH_PROCESS_BUTTON_LABEL_TEXT ,
415- svgIcon : iconLightBulb ,
416- isDisabled : this . isShowingThoughtProcess ,
417- } ,
418- ] as any } "
419318 .isDisabled ="${ this . isDisabled } "
420319 .isProcessingResponse ="${ this . chatController . isProcessingResponse } "
421- .selectedCitation ="${ this . selectedCitation } "
320+ .selectedCitation ="${ this . chatContext . selectedCitation } "
422321 .isCustomBranding ="${ this . isCustomBranding } "
423322 .svgIcon ="${ iconLogo } "
424323 .context ="${ this . chatContext } "
425- @on-action-button-click ="${ this . handleChatEntryActionButtonClick } "
426324 @on-citation-click ="${ this . handleCitationClick } "
427325 @on-followup-click ="${ this . handleInput } "
428326 >
@@ -439,9 +337,10 @@ export class ChatComponent extends LitElement {
439337
440338 // Render the chat component as a web component
441339 override render ( ) {
340+ const isAsideEnabled = this . chatSectionControllers ?. some ( ( controller ) => controller . isEnabled ) ;
442341 return html `
443- < div id ="overlay " class ="overlay "> </ div >
444- < section id ="chat__containerWrapper " class ="chat__containerWrapper ">
342+ < div id ="overlay " class ="overlay ${ isAsideEnabled ? 'active' : '' } "> </ div >
343+ < section id ="chat__containerWrapper " class ="chat__containerWrapper ${ isAsideEnabled ? 'aside-open' : '' } ">
445344 ${ this . isCustomBranding && ! this . isChatStarted
446345 ? html ` < chat-stage
447346 svgIcon ="${ iconLogo } "
@@ -528,23 +427,7 @@ export class ChatComponent extends LitElement {
528427 ) }
529428 </ form >
530429 </ section >
531- <!-- ${ this . isShowingThoughtProcess
532- ? html `
533- <aside class="aside" data-testid="aside-thought-process">
534- <div class="aside__header">
535- <chat-action-button
536- .label="${ globalConfig . HIDE_THOUGH_PROCESS_BUTTON_LABEL_TEXT } "
537- actionId="chat-hide-thought-process"
538- @click="${ this . collapseAside } "
539- .svgIcon="${ iconClose } "
540- >
541- </chat-action-button>
542- </div>
543- ${ this . renderChatEntryTabContent ( this . selectedChatEntry as ChatThreadEntry ) }
544- </aside>
545- `
546- : '' } -->
547- ${ this . chatFooterComponents ?. map ( ( component ) => component . render ( ) ) }
430+ ${ isAsideEnabled ? this . chatSectionControllers ?. map ( ( component ) => component . render ( ) ) : '' }
548431 </ section >
549432 ` ;
550433 }
0 commit comments