ソースを参照

Fix:webapp UI issues (#15601)

KVOJJJin 1 ヶ月 前
コミット
efebbffe96

+ 40 - 6
web/app/components/base/chat/chat-with-history/chat-wrapper.tsx

@@ -19,6 +19,8 @@ import {
 } from '@/service/share'
 import AppIcon from '@/app/components/base/app-icon'
 import AnswerIcon from '@/app/components/base/answer-icon'
+import SuggestedQuestions from '@/app/components/base/chat/chat/answer/suggested-questions'
+import { Markdown } from '@/app/components/base/markdown'
 import cn from '@/utils/classnames'
 
 const ChatWrapper = () => {
@@ -39,6 +41,10 @@ const ChatWrapper = () => {
     currentChatInstanceRef,
     appData,
     themeBuilder,
+    sidebarCollapseState,
+    clearChatList,
+    setClearChatList,
+    setIsResponding,
   } = useChatWithHistoryContext()
   const appConfig = useMemo(() => {
     const config = appParams || {}
@@ -58,7 +64,7 @@ const ChatWrapper = () => {
     setTargetMessageId,
     handleSend,
     handleStop,
-    isResponding,
+    isResponding: respondingState,
     suggestedQuestions,
   } = useChat(
     appConfig,
@@ -68,6 +74,8 @@ const ChatWrapper = () => {
     },
     appPrevChatTree,
     taskId => stopChatMessageResponding('', taskId, isInstalledApp, appId),
+    clearChatList,
+    setClearChatList,
   )
   const inputsFormValue = currentConversationId ? currentConversationItem?.inputs : newConversationInputsRef?.current
   const inputDisabled = useMemo(() => {
@@ -108,6 +116,10 @@ const ChatWrapper = () => {
   // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [])
 
+  useEffect(() => {
+    setIsResponding(respondingState)
+  }, [respondingState, setIsResponding])
+
   const doSend: OnSend = useCallback((message, files, isRegenerate = false, parentAnswer: ChatItem | null = null) => {
     const data: any = {
       query: message,
@@ -166,12 +178,33 @@ const ChatWrapper = () => {
 
   const welcome = useMemo(() => {
     const welcomeMessage = chatList.find(item => item.isOpeningStatement)
+    if (respondingState)
+      return null
     if (currentConversationId)
       return null
     if (!welcomeMessage)
       return null
     if (!collapsed && inputsForms.length > 0)
       return null
+    if (welcomeMessage.suggestedQuestions && welcomeMessage.suggestedQuestions?.length > 0) {
+      return (
+        <div className='h-[50vh] py-12 px-4 flex items-center justify-center'>
+          <div className='grow max-w-[720px] flex gap-4'>
+            <AppIcon
+              size='xl'
+              iconType={appData?.site.icon_type}
+              icon={appData?.site.icon}
+              background={appData?.site.icon_background}
+              imageUrl={appData?.site.icon_url}
+            />
+            <div className='grow px-4 py-3 bg-chat-bubble-bg text-text-primary rounded-2xl body-lg-regular'>
+              <Markdown content={welcomeMessage.content} />
+              <SuggestedQuestions item={welcomeMessage} />
+            </div>
+          </div>
+        </div>
+      )
+    }
     return (
       <div className={cn('h-[50vh] py-12 flex flex-col items-center justify-center gap-3')}>
         <AppIcon
@@ -181,10 +214,10 @@ const ChatWrapper = () => {
           background={appData?.site.icon_background}
           imageUrl={appData?.site.icon_url}
         />
-        <div className='text-text-tertiary body-2xl-regular'>{welcomeMessage.content}</div>
+        <Markdown className='!text-text-tertiary !body-2xl-regular' content={welcomeMessage.content} />
       </div>
     )
-  }, [appData?.site.icon, appData?.site.icon_background, appData?.site.icon_type, appData?.site.icon_url, chatList, collapsed, currentConversationId, inputsForms.length])
+  }, [appData?.site.icon, appData?.site.icon_background, appData?.site.icon_type, appData?.site.icon_url, chatList, collapsed, currentConversationId, inputsForms.length, respondingState])
 
   const answerIcon = (appData?.site && appData.site.use_icon_as_answer_icon)
     ? <AnswerIcon
@@ -203,10 +236,10 @@ const ChatWrapper = () => {
         appData={appData}
         config={appConfig}
         chatList={messageList}
-        isResponding={isResponding}
-        chatContainerInnerClassName={`mx-auto pt-6 w-full max-w-[720px] ${isMobile && 'px-4'}`}
+        isResponding={respondingState}
+        chatContainerInnerClassName={`mx-auto pt-6 w-full max-w-[768px] ${isMobile && 'px-4'}`}
         chatFooterClassName='pb-4'
-        chatFooterInnerClassName={`mx-auto w-full max-w-[720px] ${isMobile ? 'px-2' : 'px-4'}`}
+        chatFooterInnerClassName={`mx-auto w-full max-w-[768px] ${isMobile ? 'px-2' : 'px-4'}`}
         onSend={doSend}
         inputs={currentConversationId ? currentConversationItem?.inputs as any : newConversationInputs}
         inputsForm={inputsForms}
@@ -227,6 +260,7 @@ const ChatWrapper = () => {
         switchSibling={siblingMessageId => setTargetMessageId(siblingMessageId)}
         inputDisabled={inputDisabled}
         isMobile={isMobile}
+        sidebarCollapseState={sidebarCollapseState}
       />
     </div>
   )

+ 8 - 0
web/app/components/base/chat/chat-with-history/context.tsx

@@ -50,6 +50,10 @@ export type ChatWithHistoryContextValue = {
   themeBuilder?: ThemeBuilder
   sidebarCollapseState?: boolean
   handleSidebarCollapse: (state: boolean) => void
+  clearChatList?: boolean
+  setClearChatList: (state: boolean) => void
+  isResponding?: boolean
+  setIsResponding: (state: boolean) => void,
 }
 
 export const ChatWithHistoryContext = createContext<ChatWithHistoryContextValue>({
@@ -77,5 +81,9 @@ export const ChatWithHistoryContext = createContext<ChatWithHistoryContextValue>
   currentChatInstanceRef: { current: { handleStop: () => {} } },
   sidebarCollapseState: false,
   handleSidebarCollapse: () => {},
+  clearChatList: false,
+  setClearChatList: () => {},
+  isResponding: false,
+  setIsResponding: () => {},
 })
 export const useChatWithHistoryContext = () => useContext(ChatWithHistoryContext)

+ 17 - 4
web/app/components/base/chat/chat-with-history/header/index.tsx

@@ -9,7 +9,7 @@ import {
   useChatWithHistoryContext,
 } from '../context'
 import Operation from './operation'
-import ActionButton from '@/app/components/base/action-button'
+import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
 import AppIcon from '@/app/components/base/app-icon'
 import Tooltip from '@/app/components/base/tooltip'
 import ViewFormDropdown from '@/app/components/base/chat/chat-with-history/inputs-form/view-form-dropdown'
@@ -33,6 +33,7 @@ const Header = () => {
     handleNewConversation,
     sidebarCollapseState,
     handleSidebarCollapse,
+    isResponding,
   } = useChatWithHistoryContext()
   const { t } = useTranslation()
   const isSidebarCollapsed = sidebarCollapseState
@@ -106,9 +107,21 @@ const Header = () => {
             <div className='h-[14px] w-px bg-divider-regular'></div>
           </div>
           {isSidebarCollapsed && (
-            <ActionButton size='l' onClick={handleNewConversation}>
-              <RiEditBoxLine className='w-[18px] h-[18px]' />
-            </ActionButton>
+            <Tooltip
+              disabled={!!currentConversationId}
+              popupContent={t('share.chat.newChatTip')}
+            >
+              <div>
+                <ActionButton
+                  size='l'
+                  state={(!currentConversationId || isResponding) ? ActionButtonState.Disabled : ActionButtonState.Default}
+                  disabled={!currentConversationId || isResponding}
+                  onClick={handleNewConversation}
+                >
+                  <RiEditBoxLine className='w-[18px] h-[18px]' />
+                </ActionButton>
+              </div>
+            </Tooltip>
           )}
         </div>
         <div className='flex items-center gap-1'>

+ 14 - 12
web/app/components/base/chat/chat-with-history/hooks.tsx

@@ -150,6 +150,8 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
   const { data: appConversationData, isLoading: appConversationDataLoading, mutate: mutateAppConversationData } = useSWR(['appConversationData', isInstalledApp, appId, false], () => fetchConversations(isInstalledApp, appId, undefined, false, 100))
   const { data: appChatListData, isLoading: appChatListDataLoading } = useSWR(chatShouldReloadKey ? ['appChatList', chatShouldReloadKey, isInstalledApp, appId] : null, () => fetchChatList(chatShouldReloadKey, isInstalledApp, appId))
 
+  const [clearChatList, setClearChatList] = useState(false)
+  const [isResponding, setIsResponding] = useState(false)
   const appPrevChatTree = useMemo(
     () => (currentConversationId && appChatListData?.data.length)
       ? buildChatItemTree(getFormattedChatList(appChatListData.data))
@@ -310,20 +312,16 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
     currentChatInstanceRef.current.handleStop()
     setNewConversationId('')
     handleConversationIdInfoChange(conversationId)
-  }, [handleConversationIdInfoChange])
+    if (conversationId)
+      setClearChatList(false)
+  }, [handleConversationIdInfoChange, setClearChatList])
   const handleNewConversation = useCallback(() => {
     currentChatInstanceRef.current.handleStop()
-    setNewConversationId('')
-
-    if (showNewConversationItemInList) {
-      handleChangeConversation('')
-    }
-    else if (currentConversationId) {
-      handleConversationIdInfoChange('')
-      setShowNewConversationItemInList(true)
-      handleNewConversationInputsChange({})
-    }
-  }, [handleChangeConversation, currentConversationId, handleConversationIdInfoChange, setShowNewConversationItemInList, showNewConversationItemInList, handleNewConversationInputsChange])
+    setShowNewConversationItemInList(true)
+    handleChangeConversation('')
+    handleNewConversationInputsChange({})
+    setClearChatList(true)
+  }, [handleChangeConversation, setShowNewConversationItemInList, handleNewConversationInputsChange, setClearChatList])
   const handleUpdateConversationList = useCallback(() => {
     mutateAppConversationData()
     mutateAppPinnedConversationData()
@@ -462,5 +460,9 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
     currentChatInstanceRef,
     sidebarCollapseState,
     handleSidebarCollapse,
+    clearChatList,
+    setClearChatList,
+    isResponding,
+    setIsResponding,
   }
 }

+ 10 - 2
web/app/components/base/chat/chat-with-history/index.tsx

@@ -82,7 +82,7 @@ const ChatWithHistory: FC<ChatWithHistoryProps> = ({
       {isMobile && (
         <HeaderInMobile />
       )}
-      <div className={cn('relative grow p-2')}>
+      <div className={cn('relative grow p-2', isMobile && 'h-[calc(100%_-_56px)] p-0')}>
         {isSidebarCollapsed && (
           <div
             className={cn(
@@ -95,7 +95,7 @@ const ChatWithHistory: FC<ChatWithHistoryProps> = ({
             <Sidebar isPanel />
           </div>
         )}
-        <div className='h-full flex flex-col bg-chatbot-bg rounded-2xl border-[0,5px] border-components-panel-border-subtle overflow-hidden'>
+        <div className={cn('h-full flex flex-col bg-chatbot-bg border-[0,5px] border-components-panel-border-subtle overflow-hidden', isMobile ? 'rounded-t-2xl' : 'rounded-2xl')}>
           {!isMobile && <Header />}
           {appChatListDataLoading && (
             <Loading type='app' />
@@ -153,6 +153,10 @@ const ChatWithHistoryWrap: FC<ChatWithHistoryWrapProps> = ({
     currentChatInstanceRef,
     sidebarCollapseState,
     handleSidebarCollapse,
+    clearChatList,
+    setClearChatList,
+    isResponding,
+    setIsResponding,
   } = useChatWithHistory(installedAppInfo)
 
   return (
@@ -190,6 +194,10 @@ const ChatWithHistoryWrap: FC<ChatWithHistoryWrapProps> = ({
       themeBuilder,
       sidebarCollapseState,
       handleSidebarCollapse,
+      clearChatList,
+      setClearChatList,
+      isResponding,
+      setIsResponding,
     }}>
       <ChatWithHistory className={className} />
     </ChatWithHistoryContext.Provider>

+ 2 - 1
web/app/components/base/chat/chat-with-history/sidebar/index.tsx

@@ -41,6 +41,7 @@ const Sidebar = ({ isPanel }: Props) => {
     sidebarCollapseState,
     handleSidebarCollapse,
     isMobile,
+    isResponding,
   } = useChatWithHistoryContext()
   const isSidebarCollapsed = sidebarCollapseState
 
@@ -105,7 +106,7 @@ const Sidebar = ({ isPanel }: Props) => {
         )}
       </div>
       <div className='shrink-0 px-3 py-4'>
-        <Button variant='secondary-accent' className='w-full justify-center' onClick={handleNewConversation}>
+        <Button variant='secondary-accent' disabled={isResponding} className='w-full justify-center' onClick={handleNewConversation}>
           <RiEditBoxLine className='w-4 h-4 mr-1' />
           {t('share.chat.newChat')}
         </Button>

+ 1 - 1
web/app/components/base/chat/chat/answer/index.tsx

@@ -110,7 +110,7 @@ const Answer: FC<AnswerProps> = ({
           </div>
         )}
       </div>
-      <div className='chat-answer-container group grow w-0 ml-4' ref={containerRef}>
+      <div className='chat-answer-container group grow w-0 ml-4 pb-4' ref={containerRef}>
         <div className={cn('group relative pr-10', chatAnswerContainerInner)}>
           <div
             ref={contentRef}

+ 2 - 2
web/app/components/base/chat/chat/answer/operation.tsx

@@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next'
 import {
   RiClipboardLine,
   RiEditLine,
-  RiReplay15Line,
+  RiResetLeftLine,
   RiThumbDownLine,
   RiThumbUpLine,
 } from '@remixicon/react'
@@ -130,7 +130,7 @@ const Operation: FC<OperationProps> = ({
             </ActionButton>
             {!noChatInput && (
               <ActionButton onClick={() => onRegenerate?.(item)}>
-                <RiReplay15Line className='w-4 h-4' />
+                <RiResetLeftLine className='w-4 h-4' />
               </ActionButton>
             )}
             {(config?.supportAnnotation && config.annotation_reply?.enabled) && (

+ 10 - 2
web/app/components/base/chat/chat/hooks.ts

@@ -51,6 +51,8 @@ export const useChat = (
   },
   prevChatTree?: ChatItemInTree[],
   stopChat?: (taskId: string) => void,
+  clearChatList?: boolean,
+  clearChatListCallback?: (state: boolean) => void,
 ) => {
   const { t } = useTranslation()
   const { formatTime } = useTimestamp()
@@ -90,7 +92,7 @@ export const useChat = (
       }
       else {
         ret.unshift({
-          id: `${Date.now()}`,
+          id: 'opening-statement',
           content: getIntroduction(config.opening_statement),
           isAnswer: true,
           isOpeningStatement: true,
@@ -163,12 +165,13 @@ export const useChat = (
       suggestedQuestionsAbortControllerRef.current.abort()
   }, [stopChat, handleResponding])
 
-  const handleRestart = useCallback(() => {
+  const handleRestart = useCallback((cb?: any) => {
     conversationId.current = ''
     taskIdRef.current = ''
     handleStop()
     setChatTree([])
     setSuggestQuestions([])
+    cb?.()
   }, [handleStop])
 
   const updateCurrentQAOnTree = useCallback(({
@@ -682,6 +685,11 @@ export const useChat = (
     })
   }, [chatList, updateChatTreeNode])
 
+  useEffect(() => {
+    if (clearChatList)
+      handleRestart(() => clearChatListCallback?.(false))
+  }, [clearChatList, clearChatListCallback, handleRestart])
+
   return {
     chatList,
     setTargetMessageId,

+ 8 - 1
web/app/components/base/chat/chat/index.tsx

@@ -72,6 +72,7 @@ export type ChatProps = {
   noSpacing?: boolean
   inputDisabled?: boolean
   isMobile?: boolean
+  sidebarCollapseState?: boolean
 }
 
 const Chat: FC<ChatProps> = ({
@@ -110,6 +111,7 @@ const Chat: FC<ChatProps> = ({
   noSpacing,
   inputDisabled,
   isMobile,
+  sidebarCollapseState,
 }) => {
   const { t } = useTranslation()
   const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal, showAgentLogModal, setShowAgentLogModal } = useAppStore(useShallow(state => ({
@@ -193,6 +195,11 @@ const Chat: FC<ChatProps> = ({
     }
   }, [])
 
+  useEffect(() => {
+    if (!sidebarCollapseState)
+      setTimeout(() => handleWindowResize(), 200)
+  }, [sidebarCollapseState])
+
   const hasTryToAsk = config?.suggested_questions_after_answer?.enabled && !!suggestedQuestions?.length && onSend
 
   return (
@@ -255,7 +262,7 @@ const Chat: FC<ChatProps> = ({
           </div>
         </div>
         <div
-          className={`absolute bottom-0 bg-chat-input-mask ${(hasTryToAsk || !noChatInput || !noStopResponding) && chatFooterClassName}`}
+          className={`absolute bottom-0 bg-chat-input-mask flex justify-center ${(hasTryToAsk || !noChatInput || !noStopResponding) && chatFooterClassName}`}
           ref={chatFooterRef}
         >
           <div

+ 37 - 6
web/app/components/base/chat/embedded-chatbot/chat-wrapper.tsx

@@ -21,6 +21,8 @@ import {
 import AppIcon from '@/app/components/base/app-icon'
 import LogoAvatar from '@/app/components/base/logo/logo-embedded-chat-avatar'
 import AnswerIcon from '@/app/components/base/answer-icon'
+import SuggestedQuestions from '@/app/components/base/chat/chat/answer/suggested-questions'
+import { Markdown } from '@/app/components/base/markdown'
 import cn from '@/utils/classnames'
 
 const ChatWrapper = () => {
@@ -41,6 +43,9 @@ const ChatWrapper = () => {
     handleFeedback,
     currentChatInstanceRef,
     themeBuilder,
+    clearChatList,
+    setClearChatList,
+    setIsResponding,
   } = useEmbeddedChatbotContext()
   const appConfig = useMemo(() => {
     const config = appParams || {}
@@ -60,7 +65,7 @@ const ChatWrapper = () => {
     setTargetMessageId,
     handleSend,
     handleStop,
-    isResponding,
+    isResponding: respondingState,
     suggestedQuestions,
   } = useChat(
     appConfig,
@@ -70,6 +75,8 @@ const ChatWrapper = () => {
     },
     appPrevChatList,
     taskId => stopChatMessageResponding('', taskId, isInstalledApp, appId),
+    clearChatList,
+    setClearChatList,
   )
   const inputsFormValue = currentConversationId ? currentConversationItem?.inputs : newConversationInputsRef?.current
   const inputDisabled = useMemo(() => {
@@ -108,6 +115,9 @@ const ChatWrapper = () => {
     if (currentChatInstanceRef.current)
       currentChatInstanceRef.current.handleStop = handleStop
   }, [currentChatInstanceRef, handleStop])
+  useEffect(() => {
+    setIsResponding(respondingState)
+  }, [respondingState, setIsResponding])
 
   const doSend: OnSend = useCallback((message, files, isRegenerate = false, parentAnswer: ChatItem | null = null) => {
     const data: any = {
@@ -167,12 +177,33 @@ const ChatWrapper = () => {
 
   const welcome = useMemo(() => {
     const welcomeMessage = chatList.find(item => item.isOpeningStatement)
+    if (respondingState)
+      return null
     if (currentConversationId)
       return null
     if (!welcomeMessage)
       return null
     if (!collapsed && inputsForms.length > 0)
       return null
+    if (welcomeMessage.suggestedQuestions && welcomeMessage.suggestedQuestions?.length > 0) {
+      return (
+        <div className='h-[50vh] py-12 px-4 flex items-center justify-center'>
+          <div className='grow max-w-[720px] flex gap-4'>
+            <AppIcon
+              size='xl'
+              iconType={appData?.site.icon_type}
+              icon={appData?.site.icon}
+              background={appData?.site.icon_background}
+              imageUrl={appData?.site.icon_url}
+            />
+            <div className='grow px-4 py-3 bg-chat-bubble-bg text-text-primary rounded-2xl body-lg-regular'>
+              <Markdown content={welcomeMessage.content} />
+              <SuggestedQuestions item={welcomeMessage} />
+            </div>
+          </div>
+        </div>
+      )
+    }
     return (
       <div className={cn('h-[50vh] py-12 flex flex-col items-center justify-center gap-3')}>
         <AppIcon
@@ -182,10 +213,10 @@ const ChatWrapper = () => {
           background={appData?.site.icon_background}
           imageUrl={appData?.site.icon_url}
         />
-        <div className='text-text-tertiary body-2xl-regular'>{welcomeMessage.content}</div>
+        <Markdown className='!text-text-tertiary !body-2xl-regular' content={welcomeMessage.content} />
       </div>
     )
-  }, [appData?.site.icon, appData?.site.icon_background, appData?.site.icon_type, appData?.site.icon_url, chatList, collapsed, currentConversationId, inputsForms.length])
+  }, [appData?.site.icon, appData?.site.icon_background, appData?.site.icon_type, appData?.site.icon_url, chatList, collapsed, currentConversationId, inputsForms.length, respondingState])
 
   const answerIcon = isDify()
     ? <LogoAvatar className='relative shrink-0' />
@@ -203,10 +234,10 @@ const ChatWrapper = () => {
       appData={appData}
       config={appConfig}
       chatList={messageList}
-      isResponding={isResponding}
-      chatContainerInnerClassName={cn('mx-auto w-full max-w-full tablet:px-4', isMobile && 'px-4')}
+      isResponding={respondingState}
+      chatContainerInnerClassName={cn('mx-auto w-full max-w-full pt-4 tablet:px-4', isMobile && 'px-4')}
       chatFooterClassName={cn('pb-4', !isMobile && 'rounded-b-2xl')}
-      chatFooterInnerClassName={cn('mx-auto w-full max-w-full tablet:px-4', isMobile && 'px-2')}
+      chatFooterInnerClassName={cn('mx-auto w-full max-w-full px-4', isMobile && 'px-2')}
       onSend={doSend}
       inputs={currentConversationId ? currentConversationItem?.inputs as any : newConversationInputs}
       inputsForm={inputsForms}

+ 8 - 0
web/app/components/base/chat/embedded-chatbot/context.tsx

@@ -42,6 +42,10 @@ export type EmbeddedChatbotContextValue = {
   handleFeedback: (messageId: string, feedback: Feedback) => void
   currentChatInstanceRef: RefObject<{ handleStop: () => void }>
   themeBuilder?: ThemeBuilder
+  clearChatList?: boolean
+  setClearChatList: (state: boolean) => void
+  isResponding?: boolean
+  setIsResponding: (state: boolean) => void,
 }
 
 export const EmbeddedChatbotContext = createContext<EmbeddedChatbotContextValue>({
@@ -62,5 +66,9 @@ export const EmbeddedChatbotContext = createContext<EmbeddedChatbotContextValue>
   isInstalledApp: false,
   handleFeedback: () => {},
   currentChatInstanceRef: { current: { handleStop: () => {} } },
+  clearChatList: false,
+  setClearChatList: () => {},
+  isResponding: false,
+  setIsResponding: () => {},
 })
 export const useEmbeddedChatbotContext = () => useContext(EmbeddedChatbotContext)

+ 14 - 12
web/app/components/base/chat/embedded-chatbot/hooks.tsx

@@ -103,6 +103,8 @@ export const useEmbeddedChatbot = () => {
   const { data: appConversationData, isLoading: appConversationDataLoading, mutate: mutateAppConversationData } = useSWR(['appConversationData', isInstalledApp, appId, false], () => fetchConversations(isInstalledApp, appId, undefined, false, 100))
   const { data: appChatListData, isLoading: appChatListDataLoading } = useSWR(chatShouldReloadKey ? ['appChatList', chatShouldReloadKey, isInstalledApp, appId] : null, () => fetchChatList(chatShouldReloadKey, isInstalledApp, appId))
 
+  const [clearChatList, setClearChatList] = useState(false)
+  const [isResponding, setIsResponding] = useState(false)
   const appPrevChatList = useMemo(
     () => (currentConversationId && appChatListData?.data.length)
       ? buildChatItemTree(getFormattedChatList(appChatListData.data))
@@ -283,20 +285,16 @@ export const useEmbeddedChatbot = () => {
     currentChatInstanceRef.current.handleStop()
     setNewConversationId('')
     handleConversationIdInfoChange(conversationId)
-  }, [handleConversationIdInfoChange])
+    if (conversationId)
+      setClearChatList(false)
+  }, [handleConversationIdInfoChange, setClearChatList])
   const handleNewConversation = useCallback(() => {
     currentChatInstanceRef.current.handleStop()
-    setNewConversationId('')
-
-    if (showNewConversationItemInList) {
-      handleChangeConversation('')
-    }
-    else if (currentConversationId) {
-      handleConversationIdInfoChange('')
-      setShowNewConversationItemInList(true)
-      handleNewConversationInputsChange({})
-    }
-  }, [handleChangeConversation, currentConversationId, handleConversationIdInfoChange, setShowNewConversationItemInList, showNewConversationItemInList, handleNewConversationInputsChange])
+    setShowNewConversationItemInList(true)
+    handleChangeConversation('')
+    handleNewConversationInputsChange({})
+    setClearChatList(true)
+  }, [handleChangeConversation, setShowNewConversationItemInList, handleNewConversationInputsChange, setClearChatList])
 
   const handleNewConversationCompleted = useCallback((newConversationId: string) => {
     setNewConversationId(newConversationId)
@@ -342,5 +340,9 @@ export const useEmbeddedChatbot = () => {
     chatShouldReloadKey,
     handleFeedback,
     currentChatInstanceRef,
+    clearChatList,
+    setClearChatList,
+    isResponding,
+    setIsResponding,
   }
 }

+ 8 - 0
web/app/components/base/chat/embedded-chatbot/index.tsx

@@ -156,6 +156,10 @@ const EmbeddedChatbotWrapper = () => {
     appId,
     handleFeedback,
     currentChatInstanceRef,
+    clearChatList,
+    setClearChatList,
+    isResponding,
+    setIsResponding,
   } = useEmbeddedChatbot()
 
   return <EmbeddedChatbotContext.Provider value={{
@@ -185,6 +189,10 @@ const EmbeddedChatbotWrapper = () => {
     handleFeedback,
     currentChatInstanceRef,
     themeBuilder,
+    clearChatList,
+    setClearChatList,
+    isResponding,
+    setIsResponding,
   }}>
     <Chatbot />
   </EmbeddedChatbotContext.Provider>

+ 1 - 1
web/app/styles/markdown.scss

@@ -213,7 +213,7 @@
   display: block;
   width: max-content;
   max-width: 100%;
-  overflow: hidden;
+  overflow: auto;
   border: 1px solid var(--color-divider-regular);
   border-radius: 8px;
 }

+ 1 - 0
web/i18n/en-US/share-app.ts

@@ -6,6 +6,7 @@ const translation = {
   },
   chat: {
     newChat: 'Start New chat',
+    newChatTip: 'Already in a new chat',
     chatSettingsTitle: 'New chat setup',
     chatFormTip: 'Chat settings cannot be modified after the chat has started.',
     pinnedTitle: 'Pinned',

+ 1 - 0
web/i18n/zh-Hans/share-app.ts

@@ -6,6 +6,7 @@ const translation = {
   },
   chat: {
     newChat: '开启新对话',
+    newChatTip: '已在新对话中',
     chatSettingsTitle: '新对话设置',
     chatFormTip: '对话开始后,对话设置将无法修改。',
     pinnedTitle: '已置顶',