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.

index.tsx 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. 'use client'
  2. import type { FC } from 'react'
  3. import React, { useCallback, useEffect, useState } from 'react'
  4. import { useTranslation } from 'react-i18next'
  5. import Panel from '../panel'
  6. import { DataSourceType } from '../panel/types'
  7. import ConfigFirecrawlModal from './config-firecrawl-modal'
  8. import ConfigWatercrawlModal from './config-watercrawl-modal'
  9. import ConfigJinaReaderModal from './config-jina-reader-modal'
  10. import cn from '@/utils/classnames'
  11. import s from '@/app/components/datasets/create/website/index.module.css'
  12. import { fetchDataSources, removeDataSourceApiKeyBinding } from '@/service/datasets'
  13. import type { DataSourceItem } from '@/models/common'
  14. import { DataSourceProvider } from '@/models/common'
  15. import { useAppContext } from '@/context/app-context'
  16. import Toast from '@/app/components/base/toast'
  17. type Props = {
  18. provider: DataSourceProvider
  19. }
  20. const DataSourceWebsite: FC<Props> = ({ provider }) => {
  21. const { t } = useTranslation()
  22. const { isCurrentWorkspaceManager } = useAppContext()
  23. const [sources, setSources] = useState<DataSourceItem[]>([])
  24. const checkSetApiKey = useCallback(async () => {
  25. const res = await fetchDataSources() as any
  26. const list = res.sources
  27. setSources(list)
  28. }, [])
  29. useEffect(() => {
  30. checkSetApiKey()
  31. // eslint-disable-next-line react-hooks/exhaustive-deps
  32. }, [])
  33. const [configTarget, setConfigTarget] = useState<DataSourceProvider | null>(null)
  34. const showConfig = useCallback((provider: DataSourceProvider) => {
  35. setConfigTarget(provider)
  36. }, [setConfigTarget])
  37. const hideConfig = useCallback(() => {
  38. setConfigTarget(null)
  39. }, [setConfigTarget])
  40. const handleAdded = useCallback(() => {
  41. checkSetApiKey()
  42. hideConfig()
  43. }, [checkSetApiKey, hideConfig])
  44. const getIdByProvider = (provider: DataSourceProvider): string | undefined => {
  45. const source = sources.find(item => item.provider === provider)
  46. return source?.id
  47. }
  48. const getProviderName = (provider: DataSourceProvider): string => {
  49. if (provider === DataSourceProvider.fireCrawl)
  50. return 'Firecrawl'
  51. if (provider === DataSourceProvider.waterCrawl)
  52. return 'WaterCrawl'
  53. return 'Jina Reader'
  54. }
  55. const handleRemove = useCallback((provider: DataSourceProvider) => {
  56. return async () => {
  57. const dataSourceId = getIdByProvider(provider)
  58. if (dataSourceId) {
  59. await removeDataSourceApiKeyBinding(dataSourceId)
  60. setSources(sources.filter(item => item.provider !== provider))
  61. Toast.notify({
  62. type: 'success',
  63. message: t('common.api.remove'),
  64. })
  65. }
  66. }
  67. }, [sources, t])
  68. return (
  69. <>
  70. <Panel
  71. type={DataSourceType.website}
  72. provider={provider}
  73. isConfigured={sources.find(item => item.provider === provider) !== undefined}
  74. onConfigure={() => showConfig(provider)}
  75. readOnly={!isCurrentWorkspaceManager}
  76. configuredList={sources.filter(item => item.provider === provider).map(item => ({
  77. id: item.id,
  78. logo: ({ className }: { className: string }) => {
  79. if (item.provider === DataSourceProvider.fireCrawl) {
  80. return (
  81. <div
  82. className={cn(className, 'ml-3 flex h-5 w-5 items-center justify-center rounded border border-divider-subtle !bg-background-default text-xs font-medium text-text-tertiary')}>🔥</div>
  83. )
  84. }
  85. if (item.provider === DataSourceProvider.waterCrawl) {
  86. return (
  87. <div
  88. className={cn(className, 'ml-3 flex h-5 w-5 items-center justify-center rounded border border-divider-subtle !bg-background-default text-xs font-medium text-text-tertiary')}>
  89. <span className={s.watercrawlLogo}/>
  90. </div>
  91. )
  92. }
  93. return (
  94. <div
  95. className={cn(className, 'ml-3 flex h-5 w-5 items-center justify-center rounded border border-divider-subtle !bg-background-default text-xs font-medium text-text-tertiary')}>
  96. <span className={s.jinaLogo}/>
  97. </div>
  98. )
  99. },
  100. name: getProviderName(item.provider),
  101. isActive: true,
  102. }))}
  103. onRemove={handleRemove(provider)}
  104. />
  105. {configTarget === DataSourceProvider.fireCrawl && (
  106. <ConfigFirecrawlModal onSaved={handleAdded} onCancel={hideConfig}/>
  107. )}
  108. {configTarget === DataSourceProvider.waterCrawl && (
  109. <ConfigWatercrawlModal onSaved={handleAdded} onCancel={hideConfig}/>
  110. )}
  111. {configTarget === DataSourceProvider.jinaReader && (
  112. <ConfigJinaReaderModal onSaved={handleAdded} onCancel={hideConfig}/>
  113. )}
  114. </>
  115. )
  116. }
  117. export default React.memo(DataSourceWebsite)