11import React from 'react' ;
22import { useDocumentTitle } from '@app/utils/useDocumentTitle' ;
3- import { Bullseye , DropdownGroup , DropdownItem , DropdownList , Title , TitleSizes } from '@patternfly/react-core' ;
3+ import { Bullseye , DropdownGroup , DropdownItem , DropdownList , Flex , FlexItem , Title , TitleSizes } from '@patternfly/react-core' ;
44
55// Chatbot components
66import ChatbotToggle from '@patternfly/chatbot/dist/dynamic/ChatbotToggle' ;
@@ -20,6 +20,9 @@ import ChatbotHeader, {
2020 ChatbotHeaderSelectorDropdown ,
2121 ChatbotHeaderTitle
2222} from '@patternfly/chatbot/dist/dynamic/ChatbotHeader' ;
23+ import FileDropZone from '@patternfly/chatbot/dist/dynamic/FileDropZone' ;
24+ import FileDetailsLabel from '@patternfly/chatbot/dist/dynamic/FileDetailsLabel' ;
25+ import ChatbotAlert from '@patternfly/chatbot/dist/dynamic/ChatbotAlert' ;
2326
2427// Icons
2528import ExpandIcon from '@patternfly/react-icons/dist/esm/icons/expand-icon' ;
@@ -29,9 +32,7 @@ import OutlinedWindowRestoreIcon from '@patternfly/react-icons/dist/esm/icons/ou
2932// Local imports
3033import { useChatbot } from './hooks/useChatbot' ;
3134import { ToolExecutionCards } from './components/ToolExecutionCards' ;
32- import { FOOTNOTE_PROPS , INITIAL_CONVERSATIONS , INITIAL_WELCOME_PROMPTS } from './constants' ;
33- import { findMatchingItems } from './utils/helpers' ;
34- import { Conversation } from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav' ;
35+ import { FOOTNOTE_PROPS , INITIAL_WELCOME_PROMPTS } from './constants' ;
3536
3637/**
3738 * Main Lightspeed Chatbot Component
@@ -40,13 +41,13 @@ import { Conversation } from '@patternfly/chatbot/dist/dynamic/ChatbotConversati
4041 * - Model selection
4142 * - Streaming responses
4243 * - Tool execution tracking
44+ * - File attachments
4345 * - Conversation history
4446 * - Multiple display modes (overlay, docked, fullscreen)
4547 */
4648const LightspeedChatbot : React . FunctionComponent = ( ) => {
4749 useDocumentTitle ( 'Lightspeed Chatbot' ) ;
4850
49- // Use the custom hook for all chatbot logic
5051 const {
5152 chatbotVisible,
5253 displayMode,
@@ -56,18 +57,30 @@ const LightspeedChatbot: React.FunctionComponent = () => {
5657 isSendButtonDisabled,
5758 isDrawerOpen,
5859 conversations,
60+ currentConversationId,
5961 announcement,
6062 toolExecutions,
6163 scrollToBottomRef,
64+ attachedFiles,
65+ isLoadingFile,
66+ fileError,
67+ showFileAlert,
6268 onSelectModel,
6369 onSelectDisplayMode,
6470 handleSend,
71+ handleAttach,
72+ handleFileDrop,
73+ onAttachmentClose,
74+ onCloseFileAlert,
75+ handleTextInputChange,
76+ handleConversationSelect,
6577 setChatbotVisible,
6678 setMessages,
67- setConversations,
6879 setCurrentConversationId,
6980 setIsDrawerOpen
70- } = useChatbot ( ) ;
81+ } = useChatbot ( ) ;
82+
83+
7184
7285 // Enhanced message rendering with tool execution support
7386 const renderMessages = ( ) => {
@@ -113,29 +126,23 @@ const LightspeedChatbot: React.FunctionComponent = () => {
113126 displayMode = { displayMode }
114127 onDrawerToggle = { ( ) => {
115128 setIsDrawerOpen ( ! isDrawerOpen ) ;
116- setConversations ( INITIAL_CONVERSATIONS ) ;
117129 } }
118130 isDrawerOpen = { isDrawerOpen }
119131 setIsDrawerOpen = { setIsDrawerOpen }
120- activeItemId = "1"
121- // eslint-disable-next-line no-console
122- onSelectActiveItem = { ( e , selectedItem ) => console . log ( `Selected history item with id ${ selectedItem } ` ) }
132+ activeItemId = { currentConversationId }
133+ onSelectActiveItem = { ( e , selectedItem ) => {
134+ console . log ( `Selected history item with id ${ selectedItem } ` ) ;
135+ if ( typeof selectedItem === 'string' ) {
136+ handleConversationSelect ( selectedItem ) ;
137+ }
138+ } }
123139 conversations = { conversations }
124140 onNewChat = { ( ) => {
125141 setIsDrawerOpen ( ! isDrawerOpen ) ;
126142 setMessages ( [ ] ) ;
127- setConversations ( INITIAL_CONVERSATIONS ) ;
128143 setCurrentConversationId ( '' ) ;
129144 } }
130- handleTextInputChange = { ( value : string ) => {
131- if ( value === '' ) {
132- setConversations ( INITIAL_CONVERSATIONS ) ;
133- }
134- // this is where you would perform search on the items in the drawer
135- // and update the state
136- const newConversations : { [ key : string ] : Conversation [ ] } = findMatchingItems ( value ) ;
137- setConversations ( newConversations ) ;
138- } }
145+ handleTextInputChange = { handleTextInputChange }
139146 drawerContent = {
140147 < >
141148 < ChatbotHeader >
@@ -145,7 +152,7 @@ const LightspeedChatbot: React.FunctionComponent = () => {
145152 displayMode = { displayMode }
146153 showOnFullScreen = { horizontalLogo }
147154 showOnDefault = { iconLogo }
148- > </ ChatbotHeaderTitle >
155+ / >
149156 </ ChatbotHeaderMain >
150157 < ChatbotHeaderActions >
151158 < ChatbotHeaderSelectorDropdown value = { selectedModel } onSelect = { onSelectModel } >
@@ -196,32 +203,58 @@ const LightspeedChatbot: React.FunctionComponent = () => {
196203 </ ChatbotHeaderOptionsDropdown >
197204 </ ChatbotHeaderActions >
198205 </ ChatbotHeader >
199- < ChatbotContent >
200- { /* Update the announcement prop on MessageBox whenever a new message is sent
201- so that users of assistive devices receive sufficient context */ }
202- < MessageBox announcement = { announcement } >
203- < ChatbotWelcomePrompt
204- title = "Hello, Lightspeed User"
205- description = "How may I help you today?"
206- prompts = { INITIAL_WELCOME_PROMPTS }
207- />
208- { /* Display all messages */ }
209- { renderMessages ( ) }
210- { /* Scroll reference at the bottom of all messages for proper streaming behavior */ }
211- < div ref = { scrollToBottomRef } />
212- </ MessageBox >
213- </ ChatbotContent >
206+ < FileDropZone onFileDrop = { handleFileDrop } displayMode = { displayMode } >
207+ < ChatbotContent >
208+ < MessageBox announcement = { announcement } >
209+ { showFileAlert && (
210+ < ChatbotAlert
211+ variant = "danger"
212+ onClose = { onCloseFileAlert }
213+ title = "File upload failed"
214+ >
215+ { fileError }
216+ </ ChatbotAlert >
217+ ) }
218+ < ChatbotWelcomePrompt
219+ title = "Hello, Lightspeed User"
220+ description = "How may I help you today?"
221+ prompts = { INITIAL_WELCOME_PROMPTS }
222+ />
223+ { renderMessages ( ) }
224+ < div ref = { scrollToBottomRef } />
225+ </ MessageBox >
226+ </ ChatbotContent >
227+ </ FileDropZone >
214228 < ChatbotFooter >
229+ < Flex
230+ direction = { { default : 'row' } }
231+ flexWrap = { { default : 'nowrap' } }
232+ spaceItems = { { default : 'spaceItemsSm' } }
233+ style = { { overflowX : 'auto' , overflowY : 'hidden' , paddingBottom : '8px' } }
234+ >
235+ { attachedFiles . map ( ( file , index ) => (
236+ < FlexItem key = { index } flex = { { default : 'flexNone' } } >
237+ < FileDetailsLabel
238+ key = { index }
239+ fileName = { file . name }
240+ isLoading = { isLoadingFile && index === attachedFiles . length - 1 }
241+ onClose = { ( ) => onAttachmentClose ( index ) }
242+ />
243+ </ FlexItem >
244+ ) ) }
245+ </ Flex >
215246 < MessageBar
216247 onSendMessage = { handleSend }
248+ handleAttach = { handleAttach }
249+ hasAttachButton
217250 hasMicrophoneButton
218251 isSendButtonDisabled = { isSendButtonDisabled }
219252 />
220253 < ChatbotFootnote { ...FOOTNOTE_PROPS } />
221254 </ ChatbotFooter >
222255 </ >
223256 }
224- > </ ChatbotConversationHistoryNav >
257+ / >
225258 </ Chatbot >
226259 </ >
227260 ) ;
0 commit comments