您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

index.tsx 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. import type { FC } from 'react'
  2. import {
  3. useEffect,
  4. useState,
  5. } from 'react'
  6. import { useAsyncEffect } from 'ahooks'
  7. import { useThemeContext } from '../embedded-chatbot/theme/theme-context'
  8. import {
  9. ChatWithHistoryContext,
  10. useChatWithHistoryContext,
  11. } from './context'
  12. import { useChatWithHistory } from './hooks'
  13. import Sidebar from './sidebar'
  14. import Header from './header'
  15. import HeaderInMobile from './header-in-mobile'
  16. import ChatWrapper from './chat-wrapper'
  17. import type { InstalledApp } from '@/models/explore'
  18. import Loading from '@/app/components/base/loading'
  19. import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
  20. import { checkOrSetAccessToken } from '@/app/components/share/utils'
  21. import AppUnavailable from '@/app/components/base/app-unavailable'
  22. import cn from '@/utils/classnames'
  23. type ChatWithHistoryProps = {
  24. className?: string
  25. }
  26. const ChatWithHistory: FC<ChatWithHistoryProps> = ({
  27. className,
  28. }) => {
  29. const {
  30. appInfoError,
  31. appData,
  32. appInfoLoading,
  33. appChatListDataLoading,
  34. chatShouldReloadKey,
  35. isMobile,
  36. themeBuilder,
  37. sidebarCollapseState,
  38. } = useChatWithHistoryContext()
  39. const isSidebarCollapsed = sidebarCollapseState
  40. const customConfig = appData?.custom_config
  41. const site = appData?.site
  42. const [showSidePanel, setShowSidePanel] = useState(false)
  43. useEffect(() => {
  44. themeBuilder?.buildTheme(site?.chat_color_theme, site?.chat_color_theme_inverted)
  45. if (site) {
  46. if (customConfig)
  47. document.title = `${site.title}`
  48. else
  49. document.title = `${site.title} - Powered by Dify`
  50. }
  51. }, [site, customConfig, themeBuilder])
  52. if (appInfoLoading) {
  53. return (
  54. <Loading type='app' />
  55. )
  56. }
  57. if (appInfoError) {
  58. return (
  59. <AppUnavailable />
  60. )
  61. }
  62. return (
  63. <div className={cn(
  64. 'flex h-full bg-background-default-burn',
  65. isMobile && 'flex-col',
  66. className,
  67. )}>
  68. {!isMobile && (
  69. <div className={cn(
  70. 'flex w-[236px] flex-col p-1 pr-0 transition-all duration-200 ease-in-out',
  71. isSidebarCollapsed && 'w-0 overflow-hidden !p-0',
  72. )}>
  73. <Sidebar />
  74. </div>
  75. )}
  76. {isMobile && (
  77. <HeaderInMobile />
  78. )}
  79. <div className={cn('relative grow p-2', isMobile && 'h-[calc(100%_-_56px)] p-0')}>
  80. {isSidebarCollapsed && (
  81. <div
  82. className={cn(
  83. 'absolute top-0 z-20 flex h-full w-[256px] flex-col p-2 transition-all duration-500 ease-in-out',
  84. showSidePanel ? 'left-0' : 'left-[-248px]',
  85. )}
  86. onMouseEnter={() => setShowSidePanel(true)}
  87. onMouseLeave={() => setShowSidePanel(false)}
  88. >
  89. <Sidebar isPanel />
  90. </div>
  91. )}
  92. <div className={cn('flex h-full flex-col overflow-hidden border-[0,5px] border-components-panel-border-subtle bg-chatbot-bg', isMobile ? 'rounded-t-2xl' : 'rounded-2xl')}>
  93. {!isMobile && <Header />}
  94. {appChatListDataLoading && (
  95. <Loading type='app' />
  96. )}
  97. {!appChatListDataLoading && (
  98. <ChatWrapper key={chatShouldReloadKey} />
  99. )}
  100. </div>
  101. </div>
  102. </div>
  103. )
  104. }
  105. export type ChatWithHistoryWrapProps = {
  106. installedAppInfo?: InstalledApp
  107. className?: string
  108. }
  109. const ChatWithHistoryWrap: FC<ChatWithHistoryWrapProps> = ({
  110. installedAppInfo,
  111. className,
  112. }) => {
  113. const media = useBreakpoints()
  114. const isMobile = media === MediaType.mobile
  115. const themeBuilder = useThemeContext()
  116. const {
  117. appInfoError,
  118. appInfoLoading,
  119. appData,
  120. appParams,
  121. appMeta,
  122. appChatListDataLoading,
  123. currentConversationId,
  124. currentConversationItem,
  125. appPrevChatTree,
  126. pinnedConversationList,
  127. conversationList,
  128. newConversationInputs,
  129. newConversationInputsRef,
  130. handleNewConversationInputsChange,
  131. inputsForms,
  132. handleNewConversation,
  133. handleStartChat,
  134. handleChangeConversation,
  135. handlePinConversation,
  136. handleUnpinConversation,
  137. handleDeleteConversation,
  138. conversationRenaming,
  139. handleRenameConversation,
  140. handleNewConversationCompleted,
  141. chatShouldReloadKey,
  142. isInstalledApp,
  143. appId,
  144. handleFeedback,
  145. currentChatInstanceRef,
  146. sidebarCollapseState,
  147. handleSidebarCollapse,
  148. clearChatList,
  149. setClearChatList,
  150. isResponding,
  151. setIsResponding,
  152. currentConversationInputs,
  153. setCurrentConversationInputs,
  154. } = useChatWithHistory(installedAppInfo)
  155. return (
  156. <ChatWithHistoryContext.Provider value={{
  157. appInfoError,
  158. appInfoLoading,
  159. appData,
  160. appParams,
  161. appMeta,
  162. appChatListDataLoading,
  163. currentConversationId,
  164. currentConversationItem,
  165. appPrevChatTree,
  166. pinnedConversationList,
  167. conversationList,
  168. newConversationInputs,
  169. newConversationInputsRef,
  170. handleNewConversationInputsChange,
  171. inputsForms,
  172. handleNewConversation,
  173. handleStartChat,
  174. handleChangeConversation,
  175. handlePinConversation,
  176. handleUnpinConversation,
  177. handleDeleteConversation,
  178. conversationRenaming,
  179. handleRenameConversation,
  180. handleNewConversationCompleted,
  181. chatShouldReloadKey,
  182. isMobile,
  183. isInstalledApp,
  184. appId,
  185. handleFeedback,
  186. currentChatInstanceRef,
  187. themeBuilder,
  188. sidebarCollapseState,
  189. handleSidebarCollapse,
  190. clearChatList,
  191. setClearChatList,
  192. isResponding,
  193. setIsResponding,
  194. currentConversationInputs,
  195. setCurrentConversationInputs,
  196. }}>
  197. <ChatWithHistory className={className} />
  198. </ChatWithHistoryContext.Provider>
  199. )
  200. }
  201. const ChatWithHistoryWrapWithCheckToken: FC<ChatWithHistoryWrapProps> = ({
  202. installedAppInfo,
  203. className,
  204. }) => {
  205. const [initialized, setInitialized] = useState(false)
  206. const [appUnavailable, setAppUnavailable] = useState<boolean>(false)
  207. const [isUnknownReason, setIsUnknownReason] = useState<boolean>(false)
  208. useAsyncEffect(async () => {
  209. if (!initialized) {
  210. if (!installedAppInfo) {
  211. try {
  212. await checkOrSetAccessToken()
  213. }
  214. catch (e: any) {
  215. if (e.status === 404) {
  216. setAppUnavailable(true)
  217. }
  218. else {
  219. setIsUnknownReason(true)
  220. setAppUnavailable(true)
  221. }
  222. }
  223. }
  224. setInitialized(true)
  225. }
  226. }, [])
  227. if (!initialized)
  228. return null
  229. if (appUnavailable)
  230. return <AppUnavailable isUnknownReason={isUnknownReason} />
  231. return (
  232. <ChatWithHistoryWrap
  233. installedAppInfo={installedAppInfo}
  234. className={className}
  235. />
  236. )
  237. }
  238. export default ChatWithHistoryWrapWithCheckToken