mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 11:42:29 +08:00
fix: typing delay (#2200)
This commit is contained in:
parent
301e0496ff
commit
f2b2effc4b
|
@ -43,6 +43,7 @@ const IconWrapper: FC<{ children: React.ReactNode | string }> = ({ children }) =
|
|||
}
|
||||
export type IAnswerProps = {
|
||||
item: IChatItem
|
||||
index: number
|
||||
feedbackDisabled: boolean
|
||||
isHideFeedbackEdit: boolean
|
||||
onQueryChange: (query: string) => void
|
||||
|
@ -59,14 +60,15 @@ export type IAnswerProps = {
|
|||
supportAnnotation?: boolean
|
||||
appId?: string
|
||||
question: string
|
||||
onAnnotationEdited?: (question: string, answer: string) => void
|
||||
onAnnotationAdded?: (annotationId: string, authorName: string, question: string, answer: string) => void
|
||||
onAnnotationRemoved?: () => void
|
||||
onAnnotationEdited?: (question: string, answer: string, index: number) => void
|
||||
onAnnotationAdded?: (annotationId: string, authorName: string, question: string, answer: string, index: number) => void
|
||||
onAnnotationRemoved?: (index: number) => void
|
||||
allToolIcons?: Record<string, string | Emoji>
|
||||
}
|
||||
// The component needs to maintain its own state to control whether to display input component
|
||||
const Answer: FC<IAnswerProps> = ({
|
||||
item,
|
||||
index,
|
||||
onQueryChange,
|
||||
feedbackDisabled = false,
|
||||
isHideFeedbackEdit = false,
|
||||
|
@ -340,9 +342,9 @@ const Answer: FC<IAnswerProps> = ({
|
|||
cached={hasAnnotation}
|
||||
query={question}
|
||||
answer={content}
|
||||
onAdded={(id, authorName) => onAnnotationAdded?.(id, authorName, question, content)}
|
||||
onAdded={(id, authorName) => onAnnotationAdded?.(id, authorName, question, content, index)}
|
||||
onEdit={() => setIsShowReplyModal(true)}
|
||||
onRemoved={onAnnotationRemoved!}
|
||||
onRemoved={() => onAnnotationRemoved!(index)}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
@ -351,8 +353,8 @@ const Answer: FC<IAnswerProps> = ({
|
|||
onHide={() => setIsShowReplyModal(false)}
|
||||
query={question}
|
||||
answer={content}
|
||||
onEdited={onAnnotationEdited!}
|
||||
onAdded={onAnnotationAdded!}
|
||||
onEdited={(editedQuery, editedAnswer) => onAnnotationEdited!(editedQuery, editedAnswer, index)}
|
||||
onAdded={(annotationId, authorName, editedQuery, editedAnswer) => onAnnotationAdded!(annotationId, authorName, editedQuery, editedAnswer, index)}
|
||||
appId={appId!}
|
||||
messageId={id}
|
||||
annotationId={annotation?.id || ''}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
'use client'
|
||||
import type { FC, ReactNode } from 'react'
|
||||
import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'
|
||||
import Textarea from 'rc-textarea'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import cn from 'classnames'
|
||||
|
@ -197,6 +197,76 @@ const Chat: FC<IChatProps> = ({
|
|||
logError(t('common.voiceInput.notAllow'))
|
||||
})
|
||||
}
|
||||
const handleQueryChangeFromAnswer = useCallback((val: string) => {
|
||||
onQueryChange(val)
|
||||
handleSend(val)
|
||||
}, [])
|
||||
const handleAnnotationEdited = useCallback((query: string, answer: string, index: number) => {
|
||||
onChatListChange?.(chatList.map((item, i) => {
|
||||
if (i === index - 1) {
|
||||
return {
|
||||
...item,
|
||||
content: query,
|
||||
}
|
||||
}
|
||||
if (i === index) {
|
||||
return {
|
||||
...item,
|
||||
content: answer,
|
||||
annotation: {
|
||||
...item.annotation,
|
||||
logAnnotation: undefined,
|
||||
} as any,
|
||||
}
|
||||
}
|
||||
return item
|
||||
}))
|
||||
}, [])
|
||||
const handleAnnotationAdded = useCallback((annotationId: string, authorName: string, query: string, answer: string, index: number) => {
|
||||
onChatListChange?.(chatList.map((item, i) => {
|
||||
if (i === index - 1) {
|
||||
return {
|
||||
...item,
|
||||
content: query,
|
||||
}
|
||||
}
|
||||
if (i === index) {
|
||||
const answerItem = {
|
||||
...item,
|
||||
content: item.content,
|
||||
annotation: {
|
||||
id: annotationId,
|
||||
authorName,
|
||||
logAnnotation: {
|
||||
content: answer,
|
||||
account: {
|
||||
id: '',
|
||||
name: authorName,
|
||||
email: '',
|
||||
},
|
||||
},
|
||||
} as Annotation,
|
||||
}
|
||||
return answerItem
|
||||
}
|
||||
return item
|
||||
}))
|
||||
}, [])
|
||||
const handleAnnotationRemoved = useCallback((index: number) => {
|
||||
onChatListChange?.(chatList.map((item, i) => {
|
||||
if (i === index) {
|
||||
return {
|
||||
...item,
|
||||
content: item.content,
|
||||
annotation: {
|
||||
...(item.annotation || {}),
|
||||
id: '',
|
||||
} as Annotation,
|
||||
}
|
||||
}
|
||||
return item
|
||||
}))
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className={cn('px-3.5', 'h-full')}>
|
||||
|
@ -210,10 +280,8 @@ const Chat: FC<IChatProps> = ({
|
|||
return <Answer
|
||||
key={item.id}
|
||||
item={item}
|
||||
onQueryChange={(val) => {
|
||||
onQueryChange(val)
|
||||
handleSend(val)
|
||||
}}
|
||||
index={index}
|
||||
onQueryChange={handleQueryChangeFromAnswer}
|
||||
feedbackDisabled={feedbackDisabled}
|
||||
isHideFeedbackEdit={isHideFeedbackEdit}
|
||||
onFeedback={onFeedback}
|
||||
|
@ -228,72 +296,9 @@ const Chat: FC<IChatProps> = ({
|
|||
supportAnnotation={supportAnnotation}
|
||||
appId={appId}
|
||||
question={chatList[index - 1]?.content}
|
||||
onAnnotationEdited={(query, answer) => {
|
||||
onChatListChange?.(chatList.map((item, i) => {
|
||||
if (i === index - 1) {
|
||||
return {
|
||||
...item,
|
||||
content: query,
|
||||
}
|
||||
}
|
||||
if (i === index) {
|
||||
return {
|
||||
...item,
|
||||
content: answer,
|
||||
annotation: {
|
||||
...item.annotation,
|
||||
logAnnotation: undefined,
|
||||
} as any,
|
||||
}
|
||||
}
|
||||
return item
|
||||
}))
|
||||
}}
|
||||
onAnnotationAdded={(annotationId, authorName, query, answer) => {
|
||||
onChatListChange?.(chatList.map((item, i) => {
|
||||
if (i === index - 1) {
|
||||
return {
|
||||
...item,
|
||||
content: query,
|
||||
}
|
||||
}
|
||||
if (i === index) {
|
||||
const answerItem = {
|
||||
...item,
|
||||
content: item.content,
|
||||
annotation: {
|
||||
id: annotationId,
|
||||
authorName,
|
||||
logAnnotation: {
|
||||
content: answer,
|
||||
account: {
|
||||
id: '',
|
||||
name: authorName,
|
||||
email: '',
|
||||
},
|
||||
},
|
||||
} as Annotation,
|
||||
}
|
||||
return answerItem
|
||||
}
|
||||
return item
|
||||
}))
|
||||
}}
|
||||
onAnnotationRemoved={() => {
|
||||
onChatListChange?.(chatList.map((item, i) => {
|
||||
if (i === index) {
|
||||
return {
|
||||
...item,
|
||||
content: item.content,
|
||||
annotation: {
|
||||
...(item.annotation || {}),
|
||||
id: '',
|
||||
} as Annotation,
|
||||
}
|
||||
}
|
||||
return item
|
||||
}))
|
||||
}}
|
||||
onAnnotationEdited={handleAnnotationEdited}
|
||||
onAnnotationAdded={handleAnnotationAdded}
|
||||
onAnnotationRemoved={handleAnnotationRemoved}
|
||||
allToolIcons={allToolIcons}
|
||||
/>
|
||||
}
|
||||
|
@ -307,8 +312,6 @@ const Chat: FC<IChatProps> = ({
|
|||
item={item}
|
||||
isShowPromptLog={isShowPromptLog}
|
||||
isResponsing={isResponsing}
|
||||
// ['https://placekitten.com/360/360', 'https://placekitten.com/360/640']
|
||||
imgSrcs={(item.message_files && item.message_files?.length > 0) ? item.message_files.map(item => item.url) : []}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
|
|
|
@ -13,14 +13,14 @@ import ImageGallery from '@/app/components/base/image-gallery'
|
|||
type IQuestionProps = Pick<IChatItem, 'id' | 'content' | 'more' | 'useCurrentUserAvatar'> & {
|
||||
isShowPromptLog?: boolean
|
||||
item: IChatItem
|
||||
imgSrcs?: string[]
|
||||
isResponsing?: boolean
|
||||
}
|
||||
|
||||
const Question: FC<IQuestionProps> = ({ id, content, imgSrcs, more, useCurrentUserAvatar, isShowPromptLog, item, isResponsing }) => {
|
||||
const Question: FC<IQuestionProps> = ({ id, content, more, useCurrentUserAvatar, isShowPromptLog, item, isResponsing }) => {
|
||||
const { userProfile } = useContext(AppContext)
|
||||
const userName = userProfile?.name
|
||||
const ref = useRef(null)
|
||||
const imgSrcs = item.message_files?.map(item => item.url)
|
||||
|
||||
return (
|
||||
<div className={`flex items-start justify-end ${isShowPromptLog && 'first-of-type:pt-[14px]'}`} key={id} ref={ref}>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useState } from 'react'
|
||||
import { useCallback, useState } from 'react'
|
||||
import produce from 'immer'
|
||||
import { useGetState } from 'ahooks'
|
||||
import type { ConversationItem } from '@/models/share'
|
||||
|
@ -11,7 +11,7 @@ function useConversation() {
|
|||
const [pinnedConversationList, setPinnedConversationList] = useState<ConversationItem[]>([])
|
||||
const [currConversationId, doSetCurrConversationId, getCurrConversationId] = useGetState<string>('-1')
|
||||
// when set conversation id, we do not have set appId
|
||||
const setCurrConversationId = (id: string, appId: string, isSetToLocalStroge = true, newConversationName = '') => {
|
||||
const setCurrConversationId = useCallback((id: string, appId: string, isSetToLocalStroge = true, newConversationName = '') => {
|
||||
doSetCurrConversationId(id)
|
||||
if (isSetToLocalStroge && id !== '-1') {
|
||||
// conversationIdInfo: {[appId1]: conversationId1, [appId2]: conversationId2}
|
||||
|
@ -19,7 +19,7 @@ function useConversation() {
|
|||
conversationIdInfo[appId] = id
|
||||
globalThis.localStorage?.setItem(storageConversationIdKey, JSON.stringify(conversationIdInfo))
|
||||
}
|
||||
}
|
||||
}, [doSetCurrConversationId])
|
||||
|
||||
const getConversationIdFromStorage = (appId: string) => {
|
||||
const conversationIdInfo = globalThis.localStorage?.getItem(storageConversationIdKey) ? JSON.parse(globalThis.localStorage?.getItem(storageConversationIdKey) || '') : {}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable @typescript-eslint/no-use-before-define */
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import cn from 'classnames'
|
||||
import useSWR from 'swr'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
@ -65,6 +65,7 @@ const Main: FC<IMainProps> = ({
|
|||
installedAppInfo,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useContext(ToastContext)
|
||||
const media = useBreakpoints()
|
||||
const isMobile = media === MediaType.mobile
|
||||
|
||||
|
@ -123,7 +124,8 @@ const Main: FC<IMainProps> = ({
|
|||
const [suggestedQuestions, setSuggestQuestions] = useState<string[]>([])
|
||||
const [hasMore, setHasMore] = useState<boolean>(true)
|
||||
const [hasPinnedMore, setHasPinnedMore] = useState<boolean>(true)
|
||||
const onMoreLoaded = ({ data: conversations, has_more }: any) => {
|
||||
const [isShowSuggestion, setIsShowSuggestion] = useState(false)
|
||||
const onMoreLoaded = useCallback(({ data: conversations, has_more }: any) => {
|
||||
setHasMore(has_more)
|
||||
if (isClearConversationList) {
|
||||
setConversationList(conversations)
|
||||
|
@ -132,8 +134,8 @@ const Main: FC<IMainProps> = ({
|
|||
else {
|
||||
setConversationList([...conversationList, ...conversations])
|
||||
}
|
||||
}
|
||||
const onPinnedMoreLoaded = ({ data: conversations, has_more }: any) => {
|
||||
}, [conversationList, setConversationList, isClearConversationList, clearConversationListFalse])
|
||||
const onPinnedMoreLoaded = useCallback(({ data: conversations, has_more }: any) => {
|
||||
setHasPinnedMore(has_more)
|
||||
if (isClearPinnedConversationList) {
|
||||
setPinnedConversationList(conversations)
|
||||
|
@ -142,9 +144,9 @@ const Main: FC<IMainProps> = ({
|
|||
else {
|
||||
setPinnedConversationList([...pinnedConversationList, ...conversations])
|
||||
}
|
||||
}
|
||||
}, [pinnedConversationList, setPinnedConversationList, isClearPinnedConversationList, clearPinnedConversationListFalse])
|
||||
const [controlUpdateConversationList, setControlUpdateConversationList] = useState(0)
|
||||
const noticeUpdateList = () => {
|
||||
const noticeUpdateList = useCallback(() => {
|
||||
setHasMore(true)
|
||||
clearConversationListTrue()
|
||||
|
||||
|
@ -152,25 +154,25 @@ const Main: FC<IMainProps> = ({
|
|||
clearPinnedConversationListTrue()
|
||||
|
||||
setControlUpdateConversationList(Date.now())
|
||||
}
|
||||
const handlePin = async (id: string) => {
|
||||
}, [clearConversationListTrue, clearPinnedConversationListTrue])
|
||||
const handlePin = useCallback(async (id: string) => {
|
||||
await pinConversation(isInstalledApp, installedAppInfo?.id, id)
|
||||
notify({ type: 'success', message: t('common.api.success') })
|
||||
noticeUpdateList()
|
||||
}
|
||||
}, [isInstalledApp, installedAppInfo?.id, t, notify, noticeUpdateList])
|
||||
|
||||
const handleUnpin = async (id: string) => {
|
||||
const handleUnpin = useCallback(async (id: string) => {
|
||||
await unpinConversation(isInstalledApp, installedAppInfo?.id, id)
|
||||
notify({ type: 'success', message: t('common.api.success') })
|
||||
noticeUpdateList()
|
||||
}
|
||||
}, [isInstalledApp, installedAppInfo?.id, t, notify, noticeUpdateList])
|
||||
const [isShowConfirm, { setTrue: showConfirm, setFalse: hideConfirm }] = useBoolean(false)
|
||||
const [toDeleteConversationId, setToDeleteConversationId] = useState('')
|
||||
const handleDelete = (id: string) => {
|
||||
const handleDelete = useCallback((id: string) => {
|
||||
setToDeleteConversationId(id)
|
||||
hideSidebar() // mobile
|
||||
showConfirm()
|
||||
}
|
||||
}, [hideSidebar, showConfirm])
|
||||
|
||||
const didDelete = async () => {
|
||||
await delConversation(isInstalledApp, installedAppInfo?.id, toDeleteConversationId)
|
||||
|
@ -186,17 +188,51 @@ const Main: FC<IMainProps> = ({
|
|||
const [speechToTextConfig, setSpeechToTextConfig] = useState<SpeechToTextConfig | null>(null)
|
||||
const [textToSpeechConfig, setTextToSpeechConfig] = useState<TextToSpeechConfig | null>(null)
|
||||
const [citationConfig, setCitationConfig] = useState<CitationConfig | null>(null)
|
||||
|
||||
const [chatList, setChatList, getChatList] = useGetState<IChatItem[]>([])
|
||||
const chatListDomRef = useRef<HTMLDivElement>(null)
|
||||
const [isResponsing, { setTrue: setResponsingTrue, setFalse: setResponsingFalse }] = useBoolean(false)
|
||||
const [abortController, setAbortController] = useState<AbortController | null>(null)
|
||||
const [conversationIdChangeBecauseOfNew, setConversationIdChangeBecauseOfNew, getConversationIdChangeBecauseOfNew] = useGetState(false)
|
||||
const [isChatStarted, { setTrue: setChatStarted, setFalse: setChatNotStarted }] = useBoolean(false)
|
||||
const handleStartChat = (inputs: Record<string, any>) => {
|
||||
const conversationIntroduction = currConversationInfo?.introduction || ''
|
||||
const createNewChat = useCallback(async () => {
|
||||
// if new chat is already exist, do not create new chat
|
||||
abortController?.abort()
|
||||
setResponsingFalse()
|
||||
if (conversationList.some(item => item.id === '-1'))
|
||||
return
|
||||
|
||||
setConversationList(produce(conversationList, (draft) => {
|
||||
draft.unshift({
|
||||
id: '-1',
|
||||
name: t('share.chat.newChatDefaultName'),
|
||||
inputs: newConversationInputs,
|
||||
introduction: conversationIntroduction,
|
||||
})
|
||||
}))
|
||||
}, [
|
||||
abortController,
|
||||
setResponsingFalse,
|
||||
setConversationList,
|
||||
conversationList,
|
||||
newConversationInputs,
|
||||
conversationIntroduction,
|
||||
t,
|
||||
])
|
||||
const handleStartChat = useCallback((inputs: Record<string, any>) => {
|
||||
createNewChat()
|
||||
setConversationIdChangeBecauseOfNew(true)
|
||||
setCurrInputs(inputs)
|
||||
setChatStarted()
|
||||
// parse variables in introduction
|
||||
setChatList(generateNewChatListWithOpenstatement('', inputs))
|
||||
}
|
||||
}, [
|
||||
createNewChat,
|
||||
setConversationIdChangeBecauseOfNew,
|
||||
setCurrInputs,
|
||||
setChatStarted,
|
||||
setChatList,
|
||||
])
|
||||
const hasSetInputs = (() => {
|
||||
if (!isNewConversation)
|
||||
return true
|
||||
|
@ -205,7 +241,6 @@ const Main: FC<IMainProps> = ({
|
|||
})()
|
||||
|
||||
const conversationName = currConversationInfo?.name || t('share.chat.newChatDefaultName') as string
|
||||
const conversationIntroduction = currConversationInfo?.introduction || ''
|
||||
const [controlChatUpdateAllConversation, setControlChatUpdateAllConversation] = useState(0)
|
||||
|
||||
// onData change thought (the produce obj). https://github.com/immerjs/immer/issues/576
|
||||
|
@ -293,7 +328,18 @@ const Main: FC<IMainProps> = ({
|
|||
}
|
||||
useEffect(handleConversationSwitch, [currConversationId, inited])
|
||||
|
||||
const handleConversationIdChange = (id: string) => {
|
||||
/*
|
||||
* chat info. chat is under conversation.
|
||||
*/
|
||||
useEffect(() => {
|
||||
// scroll to bottom
|
||||
if (chatListDomRef.current)
|
||||
chatListDomRef.current.scrollTop = chatListDomRef.current.scrollHeight
|
||||
}, [chatList, currConversationId])
|
||||
// user can not edit inputs if user had send message
|
||||
const canEditInpus = !chatList.some(item => item.isAnswer === false) && isNewConversation
|
||||
|
||||
const handleConversationIdChange = useCallback((id: string) => {
|
||||
if (id === '-1') {
|
||||
createNewChat()
|
||||
setConversationIdChangeBecauseOfNew(true)
|
||||
|
@ -305,36 +351,14 @@ const Main: FC<IMainProps> = ({
|
|||
setCurrConversationId(id, appId)
|
||||
setIsShowSuggestion(false)
|
||||
hideSidebar()
|
||||
}
|
||||
|
||||
/*
|
||||
* chat info. chat is under conversation.
|
||||
*/
|
||||
const [chatList, setChatList, getChatList] = useGetState<IChatItem[]>([])
|
||||
const chatListDomRef = useRef<HTMLDivElement>(null)
|
||||
useEffect(() => {
|
||||
// scroll to bottom
|
||||
if (chatListDomRef.current)
|
||||
chatListDomRef.current.scrollTop = chatListDomRef.current.scrollHeight
|
||||
}, [chatList, currConversationId])
|
||||
// user can not edit inputs if user had send message
|
||||
const canEditInpus = !chatList.some(item => item.isAnswer === false) && isNewConversation
|
||||
const createNewChat = async () => {
|
||||
// if new chat is already exist, do not create new chat
|
||||
abortController?.abort()
|
||||
setResponsingFalse()
|
||||
if (conversationList.some(item => item.id === '-1'))
|
||||
return
|
||||
|
||||
setConversationList(produce(conversationList, (draft) => {
|
||||
draft.unshift({
|
||||
id: '-1',
|
||||
name: t('share.chat.newChatDefaultName'),
|
||||
inputs: newConversationInputs,
|
||||
introduction: conversationIntroduction,
|
||||
})
|
||||
}))
|
||||
}
|
||||
}, [
|
||||
appId,
|
||||
createNewChat,
|
||||
hideSidebar,
|
||||
setCurrConversationId,
|
||||
setIsShowSuggestion,
|
||||
setConversationIdChangeBecauseOfNew,
|
||||
])
|
||||
|
||||
// sometime introduction is not applied to state
|
||||
const generateNewChatListWithOpenstatement = (introduction?: string, inputs?: Record<string, any> | null) => {
|
||||
|
@ -446,14 +470,11 @@ const Main: FC<IMainProps> = ({
|
|||
})()
|
||||
}, [])
|
||||
|
||||
const [isResponsing, { setTrue: setResponsingTrue, setFalse: setResponsingFalse }] = useBoolean(false)
|
||||
const [abortController, setAbortController] = useState<AbortController | null>(null)
|
||||
const { notify } = useContext(ToastContext)
|
||||
const logError = (message: string) => {
|
||||
const logError = useCallback((message: string) => {
|
||||
notify({ type: 'error', message })
|
||||
}
|
||||
}, [notify])
|
||||
|
||||
const checkCanSend = () => {
|
||||
const checkCanSend = useCallback(() => {
|
||||
if (currConversationId !== '-1')
|
||||
return true
|
||||
|
||||
|
@ -480,10 +501,9 @@ const Main: FC<IMainProps> = ({
|
|||
return false
|
||||
}
|
||||
return !hasEmptyInput
|
||||
}
|
||||
}, [currConversationId, currInputs, promptConfig, t, logError])
|
||||
|
||||
const [controlFocus, setControlFocus] = useState(0)
|
||||
const [isShowSuggestion, setIsShowSuggestion] = useState(false)
|
||||
const doShowSuggestion = isShowSuggestion && !isResponsing
|
||||
const [openingSuggestedQuestions, setOpeningSuggestedQuestions] = useState<string[]>([])
|
||||
const [messageTaskId, setMessageTaskId] = useState('')
|
||||
|
@ -755,7 +775,7 @@ const Main: FC<IMainProps> = ({
|
|||
}, isInstalledApp, installedAppInfo?.id)
|
||||
}
|
||||
|
||||
const handleFeedback = async (messageId: string, feedback: Feedbacktype) => {
|
||||
const handleFeedback = useCallback(async (messageId: string, feedback: Feedbacktype) => {
|
||||
await updateFeedback({ url: `/messages/${messageId}/feedbacks`, body: { rating: feedback.rating } }, isInstalledApp, installedAppInfo?.id)
|
||||
const newChatList = chatList.map((item) => {
|
||||
if (item.id === messageId) {
|
||||
|
@ -768,7 +788,19 @@ const Main: FC<IMainProps> = ({
|
|||
})
|
||||
setChatList(newChatList)
|
||||
notify({ type: 'success', message: t('common.api.success') })
|
||||
}
|
||||
}, [isInstalledApp, installedAppInfo?.id, chatList, t, notify, setChatList])
|
||||
|
||||
const handleListChanged = useCallback((list: ConversationItem[]) => {
|
||||
setConversationList(list)
|
||||
setControlChatUpdateAllConversation(Date.now())
|
||||
}, [setConversationList, setControlChatUpdateAllConversation])
|
||||
const handlePinnedListChanged = useCallback((list: ConversationItem[]) => {
|
||||
setPinnedConversationList(list)
|
||||
setControlChatUpdateAllConversation(Date.now())
|
||||
}, [setPinnedConversationList, setControlChatUpdateAllConversation])
|
||||
const handleStartChatOnSidebar = useCallback(() => {
|
||||
handleConversationIdChange('-1')
|
||||
}, [handleConversationIdChange])
|
||||
|
||||
const renderSidebar = () => {
|
||||
if (!appId || !siteInfo || !promptConfig)
|
||||
|
@ -776,16 +808,10 @@ const Main: FC<IMainProps> = ({
|
|||
return (
|
||||
<Sidebar
|
||||
list={conversationList}
|
||||
onListChanged={(list) => {
|
||||
setConversationList(list)
|
||||
setControlChatUpdateAllConversation(Date.now())
|
||||
}}
|
||||
onListChanged={handleListChanged}
|
||||
isClearConversationList={isClearConversationList}
|
||||
pinnedList={pinnedConversationList}
|
||||
onPinnedListChanged={(list) => {
|
||||
setPinnedConversationList(list)
|
||||
setControlChatUpdateAllConversation(Date.now())
|
||||
}}
|
||||
onPinnedListChanged={handlePinnedListChanged}
|
||||
isClearPinnedConversationList={isClearPinnedConversationList}
|
||||
onMoreLoaded={onMoreLoaded}
|
||||
onPinnedMoreLoaded={onPinnedMoreLoaded}
|
||||
|
@ -801,11 +827,17 @@ const Main: FC<IMainProps> = ({
|
|||
onUnpin={handleUnpin}
|
||||
controlUpdateList={controlUpdateConversationList}
|
||||
onDelete={handleDelete}
|
||||
onStartChat={() => handleConversationIdChange('-1')}
|
||||
onStartChat={handleStartChatOnSidebar}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const handleAbortResponsing = useCallback(async () => {
|
||||
await stopChatMessageResponding(appId, messageTaskId, isInstalledApp, installedAppInfo?.id)
|
||||
setHasStopResponded(true)
|
||||
setResponsingFalse()
|
||||
}, [appId, messageTaskId, isInstalledApp, installedAppInfo?.id])
|
||||
|
||||
if (appUnavailable)
|
||||
return <AppUnavailable isUnknwonReason={isUnknwonReason} />
|
||||
|
||||
|
@ -824,7 +856,7 @@ const Main: FC<IMainProps> = ({
|
|||
icon_background={siteInfo.icon_background}
|
||||
isMobile={isMobile}
|
||||
onShowSideBar={showSidebar}
|
||||
onCreateNewChat={() => handleConversationIdChange('-1')}
|
||||
onCreateNewChat={handleStartChatOnSidebar}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
@ -884,11 +916,7 @@ const Main: FC<IMainProps> = ({
|
|||
onFeedback={handleFeedback}
|
||||
isResponsing={isResponsing}
|
||||
canStopResponsing={!!messageTaskId && isResponsingConIsCurrCon}
|
||||
abortResponsing={async () => {
|
||||
await stopChatMessageResponding(appId, messageTaskId, isInstalledApp, installedAppInfo?.id)
|
||||
setHasStopResponded(true)
|
||||
setResponsingFalse()
|
||||
}}
|
||||
abortResponsing={handleAbortResponsing}
|
||||
checkCanSend={checkCanSend}
|
||||
controlFocus={controlFocus}
|
||||
isShowSuggestion={doShowSuggestion}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import type { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
|
@ -76,6 +76,13 @@ const Sidebar: FC<ISidebarProps> = ({
|
|||
checkHasPinned()
|
||||
}, [controlUpdateList])
|
||||
|
||||
const handleUnpin = useCallback((id: string) => {
|
||||
onUnpin(id)
|
||||
}, [onUnpin])
|
||||
const handlePin = useCallback((id: string) => {
|
||||
onPin(id)
|
||||
}, [onPin])
|
||||
|
||||
const maxListHeight = (isInstalledApp) ? 'max-h-[30vh]' : 'max-h-[40vh]'
|
||||
|
||||
return (
|
||||
|
@ -119,7 +126,7 @@ const Sidebar: FC<ISidebarProps> = ({
|
|||
onMoreLoaded={onPinnedMoreLoaded}
|
||||
isNoMore={isPinnedNoMore}
|
||||
isPinned={true}
|
||||
onPinChanged={id => onUnpin(id)}
|
||||
onPinChanged={handleUnpin}
|
||||
controlUpdate={controlUpdateList + 1}
|
||||
onDelete={onDelete}
|
||||
/>
|
||||
|
@ -142,7 +149,7 @@ const Sidebar: FC<ISidebarProps> = ({
|
|||
onMoreLoaded={onMoreLoaded}
|
||||
isNoMore={isNoMore}
|
||||
isPinned={false}
|
||||
onPinChanged={id => onPin(id)}
|
||||
onPinChanged={handlePin}
|
||||
controlUpdate={controlUpdateList + 1}
|
||||
onDelete={onDelete}
|
||||
/>
|
||||
|
|
Loading…
Reference in New Issue
Block a user