You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. 'use client'
  2. import type { FC } from 'react'
  3. import React, { useState } from 'react'
  4. import { useTranslation } from 'react-i18next'
  5. import { useContext } from 'use-context-selector'
  6. import { RiSettings2Line } from '@remixicon/react'
  7. import ConfigCredentials from './config-credentials'
  8. import { AuthType, type Credential, type CustomCollectionBackend, type CustomParamSchema } from '@/app/components/tools/types'
  9. import Button from '@/app/components/base/button'
  10. import Input from '@/app/components/base/input'
  11. import Drawer from '@/app/components/base/drawer-plus'
  12. import I18n from '@/context/i18n'
  13. import { testAPIAvailable } from '@/service/tools'
  14. import { getLanguage } from '@/i18n-config/language'
  15. type Props = {
  16. positionCenter?: boolean
  17. customCollection: CustomCollectionBackend
  18. tool: CustomParamSchema
  19. onHide: () => void
  20. }
  21. const TestApi: FC<Props> = ({
  22. positionCenter,
  23. customCollection,
  24. tool,
  25. onHide,
  26. }) => {
  27. const { t } = useTranslation()
  28. const { locale } = useContext(I18n)
  29. const language = getLanguage(locale)
  30. const [credentialsModalShow, setCredentialsModalShow] = useState(false)
  31. const [tempCredential, setTempCredential] = React.useState<Credential>(customCollection.credentials)
  32. const [testing, setTesting] = useState(false)
  33. const [result, setResult] = useState<string>('')
  34. const { operation_id: toolName, parameters } = tool
  35. const [parametersValue, setParametersValue] = useState<Record<string, string>>({})
  36. const handleTest = async () => {
  37. if (testing) return
  38. setTesting(true)
  39. // clone test schema
  40. const credentials = JSON.parse(JSON.stringify(tempCredential)) as Credential
  41. if (credentials.auth_type === AuthType.none) {
  42. delete credentials.api_key_header_prefix
  43. delete credentials.api_key_header
  44. delete credentials.api_key_value
  45. }
  46. const data = {
  47. provider_name: customCollection.provider,
  48. tool_name: toolName,
  49. credentials,
  50. schema_type: customCollection.schema_type,
  51. schema: customCollection.schema,
  52. parameters: parametersValue,
  53. }
  54. const res = await testAPIAvailable(data) as any
  55. setResult(res.error || res.result)
  56. setTesting(false)
  57. }
  58. return (
  59. <>
  60. <Drawer
  61. isShow
  62. positionCenter={positionCenter}
  63. onHide={onHide}
  64. title={`${t('tools.test.title')} ${toolName}`}
  65. panelClassName='mt-2 !w-[600px]'
  66. maxWidthClassName='!max-w-[600px]'
  67. height='calc(100vh - 16px)'
  68. headerClassName='!border-b-divider-regular'
  69. body={
  70. <div className='overflow-y-auto px-6 pt-2'>
  71. <div className='space-y-4'>
  72. <div>
  73. <div className='system-sm-medium py-2 text-text-primary'>{t('tools.createTool.authMethod.title')}</div>
  74. <div className='flex h-9 cursor-pointer items-center justify-between rounded-lg bg-components-input-bg-normal px-2.5' onClick={() => setCredentialsModalShow(true)}>
  75. <div className='system-xs-regular text-text-primary'>{t(`tools.createTool.authMethod.types.${tempCredential.auth_type}`)}</div>
  76. <RiSettings2Line className='h-4 w-4 text-text-secondary' />
  77. </div>
  78. </div>
  79. <div>
  80. <div className='system-sm-medium py-2 text-text-primary'>{t('tools.test.parametersValue')}</div>
  81. <div className='rounded-lg border border-divider-regular'>
  82. <table className='system-xs-regular w-full font-normal text-text-secondary'>
  83. <thead className='uppercase text-text-tertiary'>
  84. <tr className='border-b border-divider-regular'>
  85. <th className="p-2 pl-3 font-medium">{t('tools.test.parameters')}</th>
  86. <th className="p-2 pl-3 font-medium">{t('tools.test.value')}</th>
  87. </tr>
  88. </thead>
  89. <tbody>
  90. {parameters.map((item, index) => (
  91. <tr key={index} className='border-b border-divider-regular last:border-0'>
  92. <td className="py-2 pl-3 pr-2.5">
  93. {item.label[language]}
  94. </td>
  95. <td className="">
  96. <Input
  97. value={parametersValue[item.name] || ''}
  98. onChange={e => setParametersValue({ ...parametersValue, [item.name]: e.target.value })}
  99. type='text'
  100. className='!hover:border-transparent !hover:bg-transparent !focus:border-transparent !focus:bg-transparent !border-transparent !bg-transparent' />
  101. </td>
  102. </tr>
  103. ))}
  104. </tbody>
  105. </table>
  106. </div>
  107. </div>
  108. </div>
  109. <Button variant='primary' className=' mt-4 h-10 w-full' loading={testing} disabled={testing} onClick={handleTest}>{t('tools.test.title')}</Button>
  110. <div className='mt-6'>
  111. <div className='flex items-center space-x-3'>
  112. <div className='system-xs-semibold text-text-tertiary'>{t('tools.test.testResult')}</div>
  113. <div className='bg-[rgb(243, 244, 246)] h-px w-0 grow'></div>
  114. </div>
  115. <div className='system-xs-regular mt-2 h-[200px] overflow-y-auto overflow-x-hidden rounded-lg bg-components-input-bg-normal px-3 py-2 text-text-secondary'>
  116. {result || <span className='text-text-quaternary'>{t('tools.test.testResultPlaceholder')}</span>}
  117. </div>
  118. </div>
  119. </div>
  120. }
  121. />
  122. {credentialsModalShow && (
  123. <ConfigCredentials
  124. positionCenter={positionCenter}
  125. credential={tempCredential}
  126. onChange={setTempCredential}
  127. onHide={() => setCredentialsModalShow(false)}
  128. />)
  129. }
  130. </>
  131. )
  132. }
  133. export default React.memo(TestApi)