| | |
| | | showFileUpload?: boolean |
| | | onFeatureBarClick?: (state: boolean) => void |
| | | noSpacing?: boolean |
| | | inputDisabled?: boolean |
| | | isMobile?: boolean |
| | | sidebarCollapseState?: boolean |
| | | } |
| | | |
| | | const Chat: FC<ChatProps> = ({ |
| | |
| | | showFileUpload, |
| | | onFeatureBarClick, |
| | | noSpacing, |
| | | inputDisabled, |
| | | isMobile, |
| | | sidebarCollapseState, |
| | | }) => { |
| | | const { t } = useTranslation() |
| | | const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal, showAgentLogModal, setShowAgentLogModal } = useAppStore(useShallow(state => ({ |
| | |
| | | |
| | | useEffect(() => { |
| | | if (chatFooterRef.current && chatContainerRef.current) { |
| | | // container padding bottom |
| | | const resizeContainerObserver = new ResizeObserver((entries) => { |
| | | const resizeObserver = new ResizeObserver((entries) => { |
| | | for (const entry of entries) { |
| | | const { blockSize } = entry.borderBoxSize[0] |
| | | |
| | | chatContainerRef.current!.style.paddingBottom = `${blockSize}px` |
| | | handleScrollToBottom() |
| | | } |
| | | }) |
| | | resizeContainerObserver.observe(chatFooterRef.current) |
| | | |
| | | // footer width |
| | | const resizeFooterObserver = new ResizeObserver((entries) => { |
| | | for (const entry of entries) { |
| | | const { inlineSize } = entry.borderBoxSize[0] |
| | | chatFooterRef.current!.style.width = `${inlineSize}px` |
| | | } |
| | | }) |
| | | resizeFooterObserver.observe(chatContainerRef.current) |
| | | resizeObserver.observe(chatFooterRef.current) |
| | | |
| | | return () => { |
| | | resizeContainerObserver.disconnect() |
| | | resizeFooterObserver.disconnect() |
| | | resizeObserver.disconnect() |
| | | } |
| | | } |
| | | }, [handleScrollToBottom]) |
| | |
| | | const chatContainer = chatContainerRef.current |
| | | if (chatContainer) { |
| | | const setUserScrolled = () => { |
| | | // eslint-disable-next-line sonarjs/no-gratuitous-expressions |
| | | if (chatContainer) // its in event callback, chatContainer may be null |
| | | userScrolledRef.current = chatContainer.scrollHeight - chatContainer.scrollTop > chatContainer.clientHeight |
| | | if (chatContainer) |
| | | userScrolledRef.current = chatContainer.scrollHeight - chatContainer.scrollTop >= chatContainer.clientHeight + 300 |
| | | } |
| | | chatContainer.addEventListener('scroll', setUserScrolled) |
| | | return () => chatContainer.removeEventListener('scroll', setUserScrolled) |
| | | } |
| | | }, []) |
| | | |
| | | useEffect(() => { |
| | | if (!sidebarCollapseState) |
| | | setTimeout(() => handleWindowResize(), 200) |
| | | }, [handleWindowResize, sidebarCollapseState]) |
| | | |
| | | const hasTryToAsk = config?.suggested_questions_after_answer?.enabled && !!suggestedQuestions?.length && onSend |
| | | |
| | |
| | | item={item} |
| | | questionIcon={questionIcon} |
| | | theme={themeBuilder?.theme} |
| | | enableEdit={config?.questionEditEnable} |
| | | switchSibling={switchSibling} |
| | | /> |
| | | ) |
| | | }) |
| | |
| | | </div> |
| | | </div> |
| | | <div |
| | | className={`absolute bottom-0 flex justify-center bg-chat-input-mask ${(hasTryToAsk || !noChatInput || !noStopResponding) && chatFooterClassName}`} |
| | | className={`absolute bottom-0 ${(hasTryToAsk || !noChatInput || !noStopResponding) && chatFooterClassName}`} |
| | | ref={chatFooterRef} |
| | | style={{ |
| | | background: 'linear-gradient(0deg, #F9FAFB 40%, rgba(255, 255, 255, 0.00) 100%)', |
| | | }} |
| | | > |
| | | <div |
| | | ref={chatFooterInnerRef} |
| | |
| | | > |
| | | { |
| | | !noStopResponding && isResponding && ( |
| | | <div className='mb-2 flex justify-center'> |
| | | <div className='flex justify-center mb-2'> |
| | | <Button onClick={onStopResponding}> |
| | | <StopCircle className='mr-[5px] h-3.5 w-3.5 text-gray-500' /> |
| | | <span className='text-xs font-normal text-gray-500'>{t('appDebug.operation.stopResponding')}</span> |
| | | <StopCircle className='mr-[5px] w-3.5 h-3.5 text-gray-500' /> |
| | | <span className='text-xs text-gray-500 font-normal'>{t('appDebug.operation.stopResponding')}</span> |
| | | </Button> |
| | | </div> |
| | | ) |
| | |
| | | <TryToAsk |
| | | suggestedQuestions={suggestedQuestions} |
| | | onSend={onSend} |
| | | isMobile={isMobile} |
| | | /> |
| | | ) |
| | | } |
| | | { |
| | | !noChatInput && ( |
| | | <ChatInputArea |
| | | disabled={inputDisabled} |
| | | showFeatureBar={showFeatureBar} |
| | | showFileUpload={showFileUpload} |
| | | featureBarDisabled={isResponding} |