index.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import { useState } from 'react'
  2. import cn from 'classnames'
  3. import s from './index.module.css'
  4. import { useContext } from 'use-context-selector'
  5. import Indicator from '../../../indicator'
  6. import { useTranslation } from 'react-i18next'
  7. import type { Provider, ProviderAzureToken } from '@/models/common'
  8. import OpenaiProvider from '../openai-provider/provider'
  9. import AzureProvider from '../azure-provider'
  10. import { ValidatedStatus } from '../provider-input/useValidateToken'
  11. import { updateProviderAIKey } from '@/service/common'
  12. import { ToastContext } from '@/app/components/base/toast'
  13. interface IProviderItemProps {
  14. icon: string
  15. name: string
  16. provider: Provider
  17. activeId: string
  18. onActive: (v: string) => void
  19. onSave: () => void
  20. }
  21. const ProviderItem = ({
  22. activeId,
  23. icon,
  24. name,
  25. provider,
  26. onActive,
  27. onSave
  28. }: IProviderItemProps) => {
  29. const { t } = useTranslation()
  30. const [validatedStatus, setValidatedStatus] = useState<ValidatedStatus>()
  31. const [loading, setLoading] = useState(false)
  32. const { notify } = useContext(ToastContext)
  33. const [token, setToken] = useState<ProviderAzureToken | string>(
  34. provider.provider_name === 'azure_openai'
  35. ? { openai_api_base: '', openai_api_key: '' }
  36. : ''
  37. )
  38. const id = `${provider.provider_name}-${provider.provider_type}`
  39. const isOpen = id === activeId
  40. const providerKey = provider.provider_name === 'azure_openai' ? (provider.token as ProviderAzureToken)?.openai_api_key : provider.token
  41. const comingSoon = false
  42. const isValid = provider.is_valid
  43. const handleUpdateToken = async () => {
  44. if (loading) return
  45. if (validatedStatus === ValidatedStatus.Success || !token) {
  46. try {
  47. setLoading(true)
  48. await updateProviderAIKey({ url: `/workspaces/current/providers/${provider.provider_name}/token`, body: { token } })
  49. notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
  50. onActive('')
  51. } catch (e) {
  52. notify({ type: 'error', message: t('common.provider.saveFailed') })
  53. } finally {
  54. setLoading(false)
  55. onSave()
  56. }
  57. }
  58. }
  59. return (
  60. <div className='mb-2 border-[0.5px] border-gray-200 bg-gray-50 rounded-md'>
  61. <div className='flex items-center px-4 h-[52px] cursor-pointer border-b-[0.5px] border-b-gray-200'>
  62. <div className={cn(s[`icon-${icon}`], 'mr-3 w-6 h-6 rounded-md')} />
  63. <div className='grow text-sm font-medium text-gray-800'>{name}</div>
  64. {
  65. providerKey && !comingSoon && !isOpen && (
  66. <div className='flex items-center mr-4'>
  67. {!isValid && <div className='text-xs text-[#D92D20]'>{t('common.provider.invalidApiKey')}</div>}
  68. <Indicator color={!isValid ? 'red' : 'green'} className='ml-2' />
  69. </div>
  70. )
  71. }
  72. {
  73. !comingSoon && !isOpen && (
  74. <div className='
  75. px-3 h-[28px] bg-white border border-gray-200 rounded-md cursor-pointer
  76. text-xs font-medium text-gray-700 flex items-center
  77. ' onClick={() => onActive(id)}>
  78. {providerKey ? t('common.provider.editKey') : t('common.provider.addKey')}
  79. </div>
  80. )
  81. }
  82. {
  83. comingSoon && !isOpen && (
  84. <div className='
  85. flex items-center px-2 h-[22px] border border-[#444CE7] rounded-md
  86. text-xs font-medium text-[#444CE7]
  87. '>
  88. {t('common.provider.comingSoon')}
  89. </div>
  90. )
  91. }
  92. {
  93. isOpen && (
  94. <div className='flex items-center'>
  95. <div className='
  96. flex items-center
  97. mr-[5px] px-3 h-7 rounded-md cursor-pointer
  98. text-xs font-medium text-gray-700
  99. ' onClick={() => onActive('')} >
  100. {t('common.operation.cancel')}
  101. </div>
  102. <div className='
  103. flex items-center
  104. px-3 h-7 rounded-md cursor-pointer bg-primary-700
  105. text-xs font-medium text-white
  106. ' onClick={handleUpdateToken}>
  107. {t('common.operation.save')}
  108. </div>
  109. </div>
  110. )
  111. }
  112. </div>
  113. {
  114. provider.provider_name === 'openai' && isOpen && (
  115. <OpenaiProvider
  116. provider={provider}
  117. onValidatedStatus={v => setValidatedStatus(v)}
  118. onTokenChange={v => setToken(v)}
  119. />
  120. )
  121. }
  122. {
  123. provider.provider_name === 'azure_openai' && isOpen && (
  124. <AzureProvider
  125. provider={provider}
  126. onValidatedStatus={v => setValidatedStatus(v)}
  127. onTokenChange={v => setToken(v)}
  128. />
  129. )
  130. }
  131. </div>
  132. )
  133. }
  134. export default ProviderItem