dify
/
web
/app
/components
/header
/account-setting
/data-source-page
/data-source-website
/index.tsx
| 'use client' | |
| import type { FC } from 'react' | |
| import React, { useCallback, useEffect, useState } from 'react' | |
| import { useTranslation } from 'react-i18next' | |
| import Panel from '../panel' | |
| import { DataSourceType } from '../panel/types' | |
| import ConfigFirecrawlModal from './config-firecrawl-modal' | |
| import ConfigJinaReaderModal from './config-jina-reader-modal' | |
| import cn from '@/utils/classnames' | |
| import s from '@/app/components/datasets/create/website/index.module.css' | |
| import { fetchDataSources, removeDataSourceApiKeyBinding } from '@/service/datasets' | |
| import type { | |
| DataSourceItem, | |
| } from '@/models/common' | |
| import { useAppContext } from '@/context/app-context' | |
| import { | |
| DataSourceProvider, | |
| } from '@/models/common' | |
| import Toast from '@/app/components/base/toast' | |
| type Props = { | |
| provider: DataSourceProvider | |
| } | |
| const DataSourceWebsite: FC<Props> = ({ provider }) => { | |
| const { t } = useTranslation() | |
| const { isCurrentWorkspaceManager } = useAppContext() | |
| const [sources, setSources] = useState<DataSourceItem[]>([]) | |
| const checkSetApiKey = useCallback(async () => { | |
| const res = await fetchDataSources() as any | |
| const list = res.sources | |
| setSources(list) | |
| }, []) | |
| useEffect(() => { | |
| checkSetApiKey() | |
| // eslint-disable-next-line react-hooks/exhaustive-deps | |
| }, []) | |
| const [configTarget, setConfigTarget] = useState<DataSourceProvider | null>(null) | |
| const showConfig = useCallback((provider: DataSourceProvider) => { | |
| setConfigTarget(provider) | |
| }, [setConfigTarget]) | |
| const hideConfig = useCallback(() => { | |
| setConfigTarget(null) | |
| }, [setConfigTarget]) | |
| const handleAdded = useCallback(() => { | |
| checkSetApiKey() | |
| hideConfig() | |
| }, [checkSetApiKey, hideConfig]) | |
| const getIdByProvider = (provider: DataSourceProvider): string | undefined => { | |
| const source = sources.find(item => item.provider === provider) | |
| return source?.id | |
| } | |
| const handleRemove = useCallback((provider: DataSourceProvider) => { | |
| return async () => { | |
| const dataSourceId = getIdByProvider(provider) | |
| if (dataSourceId) { | |
| await removeDataSourceApiKeyBinding(dataSourceId) | |
| setSources(sources.filter(item => item.provider !== provider)) | |
| Toast.notify({ | |
| type: 'success', | |
| message: t('common.api.remove'), | |
| }) | |
| } | |
| } | |
| }, [sources, t]) | |
| return ( | |
| <> | |
| <Panel | |
| type={DataSourceType.website} | |
| provider={provider} | |
| isConfigured={sources.find(item => item.provider === provider) !== undefined} | |
| onConfigure={() => showConfig(provider)} | |
| readOnly={!isCurrentWorkspaceManager} | |
| configuredList={sources.filter(item => item.provider === provider).map(item => ({ | |
| id: item.id, | |
| logo: ({ className }: { className: string }) => ( | |
| item.provider === DataSourceProvider.fireCrawl | |
| ? ( | |
| <div className={cn(className, 'flex items-center justify-center w-5 h-5 bg-white border border-gray-100 text-xs font-medium text-gray-500 rounded ml-3')}>🔥</div> | |
| ) | |
| : ( | |
| <div className={cn(className, 'flex items-center justify-center w-5 h-5 bg-white border border-gray-100 text-xs font-medium text-gray-500 rounded ml-3')}> | |
| <span className={s.jinaLogo} /> | |
| </div> | |
| ) | |
| ), | |
| name: item.provider === DataSourceProvider.fireCrawl ? 'Firecrawl' : 'Jina Reader', | |
| isActive: true, | |
| }))} | |
| onRemove={handleRemove(provider)} | |
| /> | |
| {configTarget === DataSourceProvider.fireCrawl && ( | |
| <ConfigFirecrawlModal onSaved={handleAdded} onCancel={hideConfig} /> | |
| )} | |
| {configTarget === DataSourceProvider.jinaReader && ( | |
| <ConfigJinaReaderModal onSaved={handleAdded} onCancel={hideConfig} /> | |
| )} | |
| </> | |
| ) | |
| } | |
| export default React.memo(DataSourceWebsite) | |