modal-context.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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/app/configuration/toolbox/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 type {
  13. ConfigurationMethodEnum,
  14. CustomConfigurationModelFixedFields,
  15. ModelLoadBalancingConfigEntry,
  16. ModelProvider,
  17. } from '@/app/components/header/account-setting/model-provider-page/declarations'
  18. import Pricing from '@/app/components/billing/pricing'
  19. import type { ModerationConfig } from '@/models/debug'
  20. import type {
  21. ApiBasedExtension,
  22. ExternalDataTool,
  23. } from '@/models/common'
  24. import ModelLoadBalancingEntryModal from '@/app/components/header/account-setting/model-provider-page/model-modal/model-load-balancing-entry-modal'
  25. import type { ModelLoadBalancingModalProps } from '@/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal'
  26. import ModelLoadBalancingModal from '@/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal'
  27. export type ModalState<T> = {
  28. payload: T
  29. onCancelCallback?: () => void
  30. onSaveCallback?: (newPayload: T) => void
  31. onRemoveCallback?: (newPayload: T) => void
  32. onValidateBeforeSaveCallback?: (newPayload: T) => boolean
  33. }
  34. export type ModelModalType = {
  35. currentProvider: ModelProvider
  36. currentConfigurationMethod: ConfigurationMethodEnum
  37. currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields
  38. }
  39. export type LoadBalancingEntryModalType = ModelModalType & {
  40. entry?: ModelLoadBalancingConfigEntry
  41. index?: number
  42. }
  43. export type ModalContextState = {
  44. setShowAccountSettingModal: Dispatch<SetStateAction<ModalState<string> | null>>
  45. setShowApiBasedExtensionModal: Dispatch<SetStateAction<ModalState<ApiBasedExtension> | null>>
  46. setShowModerationSettingModal: Dispatch<SetStateAction<ModalState<ModerationConfig> | null>>
  47. setShowExternalDataToolModal: Dispatch<SetStateAction<ModalState<ExternalDataTool> | null>>
  48. setShowPricingModal: () => void
  49. setShowAnnotationFullModal: () => void
  50. setShowModelModal: Dispatch<SetStateAction<ModalState<ModelModalType> | null>>
  51. setShowModelLoadBalancingModal: Dispatch<SetStateAction<ModelLoadBalancingModalProps | null>>
  52. setShowModelLoadBalancingEntryModal: Dispatch<SetStateAction<ModalState<LoadBalancingEntryModalType> | null>>
  53. }
  54. const ModalContext = createContext<ModalContextState>({
  55. setShowAccountSettingModal: () => { },
  56. setShowApiBasedExtensionModal: () => { },
  57. setShowModerationSettingModal: () => { },
  58. setShowExternalDataToolModal: () => { },
  59. setShowPricingModal: () => { },
  60. setShowAnnotationFullModal: () => { },
  61. setShowModelModal: () => { },
  62. setShowModelLoadBalancingModal: () => { },
  63. setShowModelLoadBalancingEntryModal: () => { },
  64. })
  65. export const useModalContext = () => useContext(ModalContext)
  66. // Adding a dangling comma to avoid the generic parsing issue in tsx, see:
  67. // https://github.com/microsoft/TypeScript/issues/15713
  68. // eslint-disable-next-line @typescript-eslint/comma-dangle
  69. export const useModalContextSelector = <T,>(selector: (state: ModalContextState) => T): T =>
  70. useContextSelector(ModalContext, selector)
  71. type ModalContextProviderProps = {
  72. children: React.ReactNode
  73. }
  74. export const ModalContextProvider = ({
  75. children,
  76. }: ModalContextProviderProps) => {
  77. const [showAccountSettingModal, setShowAccountSettingModal] = useState<ModalState<string> | null>(null)
  78. const [showApiBasedExtensionModal, setShowApiBasedExtensionModal] = useState<ModalState<ApiBasedExtension> | null>(null)
  79. const [showModerationSettingModal, setShowModerationSettingModal] = useState<ModalState<ModerationConfig> | null>(null)
  80. const [showExternalDataToolModal, setShowExternalDataToolModal] = useState<ModalState<ExternalDataTool> | null>(null)
  81. const [showModelModal, setShowModelModal] = useState<ModalState<ModelModalType> | null>(null)
  82. const [showModelLoadBalancingModal, setShowModelLoadBalancingModal] = useState<ModelLoadBalancingModalProps | null>(null)
  83. const [showModelLoadBalancingEntryModal, setShowModelLoadBalancingEntryModal] = useState<ModalState<LoadBalancingEntryModalType> | null>(null)
  84. const searchParams = useSearchParams()
  85. const router = useRouter()
  86. const [showPricingModal, setShowPricingModal] = useState(searchParams.get('show-pricing') === '1')
  87. const [showAnnotationFullModal, setShowAnnotationFullModal] = useState(false)
  88. const handleCancelAccountSettingModal = () => {
  89. setShowAccountSettingModal(null)
  90. if (showAccountSettingModal?.onCancelCallback)
  91. showAccountSettingModal?.onCancelCallback()
  92. }
  93. const handleCancelModerationSettingModal = () => {
  94. setShowModerationSettingModal(null)
  95. if (showModerationSettingModal?.onCancelCallback)
  96. showModerationSettingModal.onCancelCallback()
  97. }
  98. const handleCancelExternalDataToolModal = () => {
  99. setShowExternalDataToolModal(null)
  100. if (showExternalDataToolModal?.onCancelCallback)
  101. showExternalDataToolModal.onCancelCallback()
  102. }
  103. const handleCancelModelModal = useCallback(() => {
  104. setShowModelModal(null)
  105. if (showModelModal?.onCancelCallback)
  106. showModelModal.onCancelCallback()
  107. }, [showModelModal])
  108. const handleSaveModelModal = useCallback(() => {
  109. if (showModelModal?.onSaveCallback)
  110. showModelModal.onSaveCallback(showModelModal.payload)
  111. setShowModelModal(null)
  112. }, [showModelModal])
  113. const handleCancelModelLoadBalancingEntryModal = useCallback(() => {
  114. showModelLoadBalancingEntryModal?.onCancelCallback?.()
  115. setShowModelLoadBalancingEntryModal(null)
  116. }, [showModelLoadBalancingEntryModal])
  117. const handleSaveModelLoadBalancingEntryModal = useCallback((entry: ModelLoadBalancingConfigEntry) => {
  118. showModelLoadBalancingEntryModal?.onSaveCallback?.({
  119. ...showModelLoadBalancingEntryModal.payload,
  120. entry,
  121. })
  122. setShowModelLoadBalancingEntryModal(null)
  123. }, [showModelLoadBalancingEntryModal])
  124. const handleRemoveModelLoadBalancingEntry = useCallback(() => {
  125. showModelLoadBalancingEntryModal?.onRemoveCallback?.(showModelLoadBalancingEntryModal.payload)
  126. setShowModelLoadBalancingEntryModal(null)
  127. }, [showModelLoadBalancingEntryModal])
  128. const handleSaveApiBasedExtension = (newApiBasedExtension: ApiBasedExtension) => {
  129. if (showApiBasedExtensionModal?.onSaveCallback)
  130. showApiBasedExtensionModal.onSaveCallback(newApiBasedExtension)
  131. setShowApiBasedExtensionModal(null)
  132. }
  133. const handleSaveModeration = (newModerationConfig: ModerationConfig) => {
  134. if (showModerationSettingModal?.onSaveCallback)
  135. showModerationSettingModal.onSaveCallback(newModerationConfig)
  136. setShowModerationSettingModal(null)
  137. }
  138. const handleSaveExternalDataTool = (newExternalDataTool: ExternalDataTool) => {
  139. if (showExternalDataToolModal?.onSaveCallback)
  140. showExternalDataToolModal.onSaveCallback(newExternalDataTool)
  141. setShowExternalDataToolModal(null)
  142. }
  143. const handleValidateBeforeSaveExternalDataTool = (newExternalDataTool: ExternalDataTool) => {
  144. if (showExternalDataToolModal?.onValidateBeforeSaveCallback)
  145. return showExternalDataToolModal?.onValidateBeforeSaveCallback(newExternalDataTool)
  146. return true
  147. }
  148. return (
  149. <ModalContext.Provider value={{
  150. setShowAccountSettingModal,
  151. setShowApiBasedExtensionModal,
  152. setShowModerationSettingModal,
  153. setShowExternalDataToolModal,
  154. setShowPricingModal: () => setShowPricingModal(true),
  155. setShowAnnotationFullModal: () => setShowAnnotationFullModal(true),
  156. setShowModelModal,
  157. setShowModelLoadBalancingModal,
  158. setShowModelLoadBalancingEntryModal,
  159. }}>
  160. <>
  161. {children}
  162. {
  163. !!showAccountSettingModal && (
  164. <AccountSetting
  165. activeTab={showAccountSettingModal.payload}
  166. onCancel={handleCancelAccountSettingModal}
  167. />
  168. )
  169. }
  170. {
  171. !!showApiBasedExtensionModal && (
  172. <ApiBasedExtensionModal
  173. data={showApiBasedExtensionModal.payload}
  174. onCancel={() => setShowApiBasedExtensionModal(null)}
  175. onSave={handleSaveApiBasedExtension}
  176. />
  177. )
  178. }
  179. {
  180. !!showModerationSettingModal && (
  181. <ModerationSettingModal
  182. data={showModerationSettingModal.payload}
  183. onCancel={handleCancelModerationSettingModal}
  184. onSave={handleSaveModeration}
  185. />
  186. )
  187. }
  188. {
  189. !!showExternalDataToolModal && (
  190. <ExternalDataToolModal
  191. data={showExternalDataToolModal.payload}
  192. onCancel={handleCancelExternalDataToolModal}
  193. onSave={handleSaveExternalDataTool}
  194. onValidateBeforeSave={handleValidateBeforeSaveExternalDataTool}
  195. />
  196. )
  197. }
  198. {
  199. !!showPricingModal && (
  200. <Pricing onCancel={() => {
  201. if (searchParams.get('show-pricing') === '1')
  202. router.push(location.pathname, { forceOptimisticNavigation: true } as any)
  203. setShowPricingModal(false)
  204. }} />
  205. )
  206. }
  207. {
  208. showAnnotationFullModal && (
  209. <AnnotationFullModal
  210. show={showAnnotationFullModal}
  211. onHide={() => setShowAnnotationFullModal(false)} />
  212. )
  213. }
  214. {
  215. !!showModelModal && (
  216. <ModelModal
  217. provider={showModelModal.payload.currentProvider}
  218. configurateMethod={showModelModal.payload.currentConfigurationMethod}
  219. currentCustomConfigurationModelFixedFields={showModelModal.payload.currentCustomConfigurationModelFixedFields}
  220. onCancel={handleCancelModelModal}
  221. onSave={handleSaveModelModal}
  222. />
  223. )
  224. }
  225. {
  226. Boolean(showModelLoadBalancingModal) && (
  227. <ModelLoadBalancingModal {...showModelLoadBalancingModal!} />
  228. )
  229. }
  230. {
  231. !!showModelLoadBalancingEntryModal && (
  232. <ModelLoadBalancingEntryModal
  233. provider={showModelLoadBalancingEntryModal.payload.currentProvider}
  234. configurationMethod={showModelLoadBalancingEntryModal.payload.currentConfigurationMethod}
  235. currentCustomConfigurationModelFixedFields={showModelLoadBalancingEntryModal.payload.currentCustomConfigurationModelFixedFields}
  236. entry={showModelLoadBalancingEntryModal.payload.entry}
  237. onCancel={handleCancelModelLoadBalancingEntryModal}
  238. onSave={handleSaveModelLoadBalancingEntryModal}
  239. onRemove={handleRemoveModelLoadBalancingEntry}
  240. />
  241. )
  242. }
  243. </>
  244. </ModalContext.Provider>
  245. )
  246. }
  247. export default ModalContext