modal-context.tsx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. 'use client'
  2. import type { Dispatch, SetStateAction } from 'react'
  3. import { useCallback, useState } from 'react'
  4. import { createContext, useContext, useContextSelector } from 'use-context-selector'
  5. import { useRouter, useSearchParams } from 'next/navigation'
  6. import AccountSetting from '@/app/components/header/account-setting'
  7. import ApiBasedExtensionModal from '@/app/components/header/account-setting/api-based-extension-page/modal'
  8. import ModerationSettingModal from '@/app/components/base/features/new-feature-panel/moderation/moderation-setting-modal'
  9. import ExternalDataToolModal from '@/app/components/app/configuration/tools/external-data-tool-modal'
  10. import AnnotationFullModal from '@/app/components/billing/annotation-full/modal'
  11. import ModelModal from '@/app/components/header/account-setting/model-provider-page/model-modal'
  12. import ExternalAPIModal from '@/app/components/datasets/external-api/external-api-modal'
  13. import type {
  14. ConfigurationMethodEnum,
  15. CustomConfigurationModelFixedFields,
  16. ModelLoadBalancingConfigEntry,
  17. ModelProvider,
  18. } from '@/app/components/header/account-setting/model-provider-page/declarations'
  19. import Pricing from '@/app/components/billing/pricing'
  20. import type { ModerationConfig, PromptVariable } from '@/models/debug'
  21. import type {
  22. ApiBasedExtension,
  23. ExternalDataTool,
  24. } from '@/models/common'
  25. import type { CreateExternalAPIReq } from '@/app/components/datasets/external-api/declarations'
  26. import ModelLoadBalancingEntryModal from '@/app/components/header/account-setting/model-provider-page/model-modal/model-load-balancing-entry-modal'
  27. import type { ModelLoadBalancingModalProps } from '@/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal'
  28. import ModelLoadBalancingModal from '@/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal'
  29. import OpeningSettingModal from '@/app/components/base/features/new-feature-panel/conversation-opener/modal'
  30. import type { OpeningStatement } from '@/app/components/base/features/types'
  31. import type { InputVar } from '@/app/components/workflow/types'
  32. export type ModalState<T> = {
  33. payload: T
  34. onCancelCallback?: () => void
  35. onSaveCallback?: (newPayload: T) => void
  36. onRemoveCallback?: (newPayload: T) => void
  37. onEditCallback?: (newPayload: T) => void
  38. onValidateBeforeSaveCallback?: (newPayload: T) => boolean
  39. isEditMode?: boolean
  40. datasetBindings?: { id: string; name: string }[]
  41. }
  42. export type ModelModalType = {
  43. currentProvider: ModelProvider
  44. currentConfigurationMethod: ConfigurationMethodEnum
  45. currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields
  46. }
  47. export type LoadBalancingEntryModalType = ModelModalType & {
  48. entry?: ModelLoadBalancingConfigEntry
  49. index?: number
  50. }
  51. export type ModalContextState = {
  52. setShowAccountSettingModal: Dispatch<SetStateAction<ModalState<string> | null>>
  53. setShowApiBasedExtensionModal: Dispatch<SetStateAction<ModalState<ApiBasedExtension> | null>>
  54. setShowModerationSettingModal: Dispatch<SetStateAction<ModalState<ModerationConfig> | null>>
  55. setShowExternalDataToolModal: Dispatch<SetStateAction<ModalState<ExternalDataTool> | null>>
  56. setShowPricingModal: () => void
  57. setShowAnnotationFullModal: () => void
  58. setShowModelModal: Dispatch<SetStateAction<ModalState<ModelModalType> | null>>
  59. setShowExternalKnowledgeAPIModal: Dispatch<SetStateAction<ModalState<CreateExternalAPIReq> | null>>
  60. setShowModelLoadBalancingModal: Dispatch<SetStateAction<ModelLoadBalancingModalProps | null>>
  61. setShowModelLoadBalancingEntryModal: Dispatch<SetStateAction<ModalState<LoadBalancingEntryModalType> | null>>
  62. setShowOpeningModal: Dispatch<SetStateAction<ModalState<OpeningStatement & {
  63. promptVariables?: PromptVariable[]
  64. workflowVariables?: InputVar[]
  65. onAutoAddPromptVariable?: (variable: PromptVariable[]) => void
  66. }> | null>>
  67. }
  68. const ModalContext = createContext<ModalContextState>({
  69. setShowAccountSettingModal: () => { },
  70. setShowApiBasedExtensionModal: () => { },
  71. setShowModerationSettingModal: () => { },
  72. setShowExternalDataToolModal: () => { },
  73. setShowPricingModal: () => { },
  74. setShowAnnotationFullModal: () => { },
  75. setShowModelModal: () => { },
  76. setShowExternalKnowledgeAPIModal: () => { },
  77. setShowModelLoadBalancingModal: () => { },
  78. setShowModelLoadBalancingEntryModal: () => { },
  79. setShowOpeningModal: () => { },
  80. })
  81. export const useModalContext = () => useContext(ModalContext)
  82. // Adding a dangling comma to avoid the generic parsing issue in tsx, see:
  83. // https://github.com/microsoft/TypeScript/issues/15713
  84. // eslint-disable-next-line @typescript-eslint/comma-dangle
  85. export const useModalContextSelector = <T,>(selector: (state: ModalContextState) => T): T =>
  86. useContextSelector(ModalContext, selector)
  87. type ModalContextProviderProps = {
  88. children: React.ReactNode
  89. }
  90. export const ModalContextProvider = ({
  91. children,
  92. }: ModalContextProviderProps) => {
  93. const [showAccountSettingModal, setShowAccountSettingModal] = useState<ModalState<string> | null>(null)
  94. const [showApiBasedExtensionModal, setShowApiBasedExtensionModal] = useState<ModalState<ApiBasedExtension> | null>(null)
  95. const [showModerationSettingModal, setShowModerationSettingModal] = useState<ModalState<ModerationConfig> | null>(null)
  96. const [showExternalDataToolModal, setShowExternalDataToolModal] = useState<ModalState<ExternalDataTool> | null>(null)
  97. const [showModelModal, setShowModelModal] = useState<ModalState<ModelModalType> | null>(null)
  98. const [showExternalKnowledgeAPIModal, setShowExternalKnowledgeAPIModal] = useState<ModalState<CreateExternalAPIReq> | null>(null)
  99. const [showModelLoadBalancingModal, setShowModelLoadBalancingModal] = useState<ModelLoadBalancingModalProps | null>(null)
  100. const [showModelLoadBalancingEntryModal, setShowModelLoadBalancingEntryModal] = useState<ModalState<LoadBalancingEntryModalType> | null>(null)
  101. const [showOpeningModal, setShowOpeningModal] = useState<ModalState<OpeningStatement & {
  102. promptVariables?: PromptVariable[]
  103. workflowVariables?: InputVar[]
  104. onAutoAddPromptVariable?: (variable: PromptVariable[]) => void
  105. }> | null>(null)
  106. const searchParams = useSearchParams()
  107. const router = useRouter()
  108. const [showPricingModal, setShowPricingModal] = useState(searchParams.get('show-pricing') === '1')
  109. const [showAnnotationFullModal, setShowAnnotationFullModal] = useState(false)
  110. const handleCancelAccountSettingModal = () => {
  111. setShowAccountSettingModal(null)
  112. if (showAccountSettingModal?.onCancelCallback)
  113. showAccountSettingModal?.onCancelCallback()
  114. }
  115. const handleCancelModerationSettingModal = () => {
  116. setShowModerationSettingModal(null)
  117. if (showModerationSettingModal?.onCancelCallback)
  118. showModerationSettingModal.onCancelCallback()
  119. }
  120. const handleCancelExternalDataToolModal = () => {
  121. setShowExternalDataToolModal(null)
  122. if (showExternalDataToolModal?.onCancelCallback)
  123. showExternalDataToolModal.onCancelCallback()
  124. }
  125. const handleCancelModelModal = useCallback(() => {
  126. setShowModelModal(null)
  127. if (showModelModal?.onCancelCallback)
  128. showModelModal.onCancelCallback()
  129. }, [showModelModal])
  130. const handleSaveModelModal = useCallback(() => {
  131. if (showModelModal?.onSaveCallback)
  132. showModelModal.onSaveCallback(showModelModal.payload)
  133. setShowModelModal(null)
  134. }, [showModelModal])
  135. const handleCancelExternalApiModal = useCallback(() => {
  136. setShowExternalKnowledgeAPIModal(null)
  137. if (showExternalKnowledgeAPIModal?.onCancelCallback)
  138. showExternalKnowledgeAPIModal.onCancelCallback()
  139. }, [showExternalKnowledgeAPIModal])
  140. const handleSaveExternalApiModal = useCallback(async (updatedFormValue: CreateExternalAPIReq) => {
  141. if (showExternalKnowledgeAPIModal?.onSaveCallback)
  142. showExternalKnowledgeAPIModal.onSaveCallback(updatedFormValue)
  143. setShowExternalKnowledgeAPIModal(null)
  144. }, [showExternalKnowledgeAPIModal])
  145. const handleEditExternalApiModal = useCallback(async (updatedFormValue: CreateExternalAPIReq) => {
  146. if (showExternalKnowledgeAPIModal?.onEditCallback)
  147. showExternalKnowledgeAPIModal.onEditCallback(updatedFormValue)
  148. setShowExternalKnowledgeAPIModal(null)
  149. }, [showExternalKnowledgeAPIModal])
  150. const handleCancelModelLoadBalancingEntryModal = useCallback(() => {
  151. showModelLoadBalancingEntryModal?.onCancelCallback?.()
  152. setShowModelLoadBalancingEntryModal(null)
  153. }, [showModelLoadBalancingEntryModal])
  154. const handleCancelOpeningModal = useCallback(() => {
  155. setShowOpeningModal(null)
  156. if (showOpeningModal?.onCancelCallback)
  157. showOpeningModal.onCancelCallback()
  158. }, [showOpeningModal])
  159. const handleSaveModelLoadBalancingEntryModal = useCallback((entry: ModelLoadBalancingConfigEntry) => {
  160. showModelLoadBalancingEntryModal?.onSaveCallback?.({
  161. ...showModelLoadBalancingEntryModal.payload,
  162. entry,
  163. })
  164. setShowModelLoadBalancingEntryModal(null)
  165. }, [showModelLoadBalancingEntryModal])
  166. const handleRemoveModelLoadBalancingEntry = useCallback(() => {
  167. showModelLoadBalancingEntryModal?.onRemoveCallback?.(showModelLoadBalancingEntryModal.payload)
  168. setShowModelLoadBalancingEntryModal(null)
  169. }, [showModelLoadBalancingEntryModal])
  170. const handleSaveApiBasedExtension = (newApiBasedExtension: ApiBasedExtension) => {
  171. if (showApiBasedExtensionModal?.onSaveCallback)
  172. showApiBasedExtensionModal.onSaveCallback(newApiBasedExtension)
  173. setShowApiBasedExtensionModal(null)
  174. }
  175. const handleSaveModeration = (newModerationConfig: ModerationConfig) => {
  176. if (showModerationSettingModal?.onSaveCallback)
  177. showModerationSettingModal.onSaveCallback(newModerationConfig)
  178. setShowModerationSettingModal(null)
  179. }
  180. const handleSaveExternalDataTool = (newExternalDataTool: ExternalDataTool) => {
  181. if (showExternalDataToolModal?.onSaveCallback)
  182. showExternalDataToolModal.onSaveCallback(newExternalDataTool)
  183. setShowExternalDataToolModal(null)
  184. }
  185. const handleValidateBeforeSaveExternalDataTool = (newExternalDataTool: ExternalDataTool) => {
  186. if (showExternalDataToolModal?.onValidateBeforeSaveCallback)
  187. return showExternalDataToolModal?.onValidateBeforeSaveCallback(newExternalDataTool)
  188. return true
  189. }
  190. const handleSaveOpeningModal = (newOpening: OpeningStatement) => {
  191. if (showOpeningModal?.onSaveCallback)
  192. showOpeningModal.onSaveCallback(newOpening)
  193. setShowOpeningModal(null)
  194. }
  195. return (
  196. <ModalContext.Provider value={{
  197. setShowAccountSettingModal,
  198. setShowApiBasedExtensionModal,
  199. setShowModerationSettingModal,
  200. setShowExternalDataToolModal,
  201. setShowPricingModal: () => setShowPricingModal(true),
  202. setShowAnnotationFullModal: () => setShowAnnotationFullModal(true),
  203. setShowModelModal,
  204. setShowExternalKnowledgeAPIModal,
  205. setShowModelLoadBalancingModal,
  206. setShowModelLoadBalancingEntryModal,
  207. setShowOpeningModal,
  208. }}>
  209. <>
  210. {children}
  211. {
  212. !!showAccountSettingModal && (
  213. <AccountSetting
  214. activeTab={showAccountSettingModal.payload}
  215. onCancel={handleCancelAccountSettingModal}
  216. />
  217. )
  218. }
  219. {
  220. !!showApiBasedExtensionModal && (
  221. <ApiBasedExtensionModal
  222. data={showApiBasedExtensionModal.payload}
  223. onCancel={() => setShowApiBasedExtensionModal(null)}
  224. onSave={handleSaveApiBasedExtension}
  225. />
  226. )
  227. }
  228. {
  229. !!showModerationSettingModal && (
  230. <ModerationSettingModal
  231. data={showModerationSettingModal.payload}
  232. onCancel={handleCancelModerationSettingModal}
  233. onSave={handleSaveModeration}
  234. />
  235. )
  236. }
  237. {
  238. !!showExternalDataToolModal && (
  239. <ExternalDataToolModal
  240. data={showExternalDataToolModal.payload}
  241. onCancel={handleCancelExternalDataToolModal}
  242. onSave={handleSaveExternalDataTool}
  243. onValidateBeforeSave={handleValidateBeforeSaveExternalDataTool}
  244. />
  245. )
  246. }
  247. {
  248. !!showPricingModal && (
  249. <Pricing onCancel={() => {
  250. if (searchParams.get('show-pricing') === '1')
  251. router.push(location.pathname, { forceOptimisticNavigation: true } as any)
  252. setShowPricingModal(false)
  253. }} />
  254. )
  255. }
  256. {
  257. showAnnotationFullModal && (
  258. <AnnotationFullModal
  259. show={showAnnotationFullModal}
  260. onHide={() => setShowAnnotationFullModal(false)} />
  261. )
  262. }
  263. {
  264. !!showModelModal && (
  265. <ModelModal
  266. provider={showModelModal.payload.currentProvider}
  267. configurateMethod={showModelModal.payload.currentConfigurationMethod}
  268. currentCustomConfigurationModelFixedFields={showModelModal.payload.currentCustomConfigurationModelFixedFields}
  269. onCancel={handleCancelModelModal}
  270. onSave={handleSaveModelModal}
  271. />
  272. )
  273. }
  274. {
  275. !!showExternalKnowledgeAPIModal && (
  276. <ExternalAPIModal
  277. data={showExternalKnowledgeAPIModal.payload}
  278. datasetBindings={showExternalKnowledgeAPIModal.datasetBindings ?? []}
  279. onSave={handleSaveExternalApiModal}
  280. onCancel={handleCancelExternalApiModal}
  281. onEdit={handleEditExternalApiModal}
  282. isEditMode={showExternalKnowledgeAPIModal.isEditMode ?? false}
  283. />
  284. )
  285. }
  286. {
  287. Boolean(showModelLoadBalancingModal) && (
  288. <ModelLoadBalancingModal {...showModelLoadBalancingModal!} />
  289. )
  290. }
  291. {
  292. !!showModelLoadBalancingEntryModal && (
  293. <ModelLoadBalancingEntryModal
  294. provider={showModelLoadBalancingEntryModal.payload.currentProvider}
  295. configurationMethod={showModelLoadBalancingEntryModal.payload.currentConfigurationMethod}
  296. currentCustomConfigurationModelFixedFields={showModelLoadBalancingEntryModal.payload.currentCustomConfigurationModelFixedFields}
  297. entry={showModelLoadBalancingEntryModal.payload.entry}
  298. onCancel={handleCancelModelLoadBalancingEntryModal}
  299. onSave={handleSaveModelLoadBalancingEntryModal}
  300. onRemove={handleRemoveModelLoadBalancingEntry}
  301. />
  302. )
  303. }
  304. {showOpeningModal && (
  305. <OpeningSettingModal
  306. data={showOpeningModal.payload}
  307. onSave={handleSaveOpeningModal}
  308. onCancel={handleCancelOpeningModal}
  309. promptVariables={showOpeningModal.payload.promptVariables}
  310. workflowVariables={showOpeningModal.payload.workflowVariables}
  311. onAutoAddPromptVariable={showOpeningModal.payload.onAutoAddPromptVariable}
  312. />
  313. )}
  314. </>
  315. </ModalContext.Provider>
  316. )
  317. }
  318. export default ModalContext