fix: Add dataset file upload restrictions (#29397)

Co-authored-by: kurokobo <kuro664@gmail.com>
Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com>
This commit is contained in:
Wu Tianwei 2025-12-10 16:41:05 +08:00 committed by GitHub
parent 88b20bc6d0
commit bafd093fa9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
35 changed files with 206 additions and 151 deletions

View File

@ -21,6 +21,7 @@ type NotionPageSelectorProps = {
datasetId?: string
credentialList: DataSourceCredential[]
onSelectCredential?: (credentialId: string) => void
supportBatchUpload?: boolean
}
const NotionPageSelector = ({
@ -32,6 +33,7 @@ const NotionPageSelector = ({
datasetId = '',
credentialList,
onSelectCredential,
supportBatchUpload = false,
}: NotionPageSelectorProps) => {
const [searchValue, setSearchValue] = useState('')
const setShowAccountSettingModal = useModalContextSelector(s => s.setShowAccountSettingModal)
@ -110,7 +112,7 @@ const NotionPageSelector = ({
setCurrentCredential(credential)
onSelect([]) // Clear selected pages when changing credential
onSelectCredential?.(credential.credentialId)
}, [invalidPreImportNotionPages, onSelect, onSelectCredential])
}, [datasetId, invalidPreImportNotionPages, notionCredentials, onSelect, onSelectCredential])
const handleSelectPages = useCallback((newSelectedPagesId: Set<string>) => {
const selectedPages = Array.from(newSelectedPagesId).map(pageId => pagesMapAndSelectedPagesId[0][pageId])
@ -175,6 +177,7 @@ const NotionPageSelector = ({
canPreview={canPreview}
previewPageId={previewPageId}
onPreview={handlePreviewPage}
isMultipleChoice={supportBatchUpload}
/>
)}
</div>

View File

@ -1,9 +1,8 @@
'use client'
import { useTranslation } from 'react-i18next'
import React, { Fragment, useMemo } from 'react'
import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
import { RiArrowDownSLine } from '@remixicon/react'
import NotionIcon from '../../notion-icon'
import { CredentialIcon } from '@/app/components/datasets/common/credential-icon'
export type NotionCredential = {
credentialId: string
@ -23,14 +22,10 @@ const CredentialSelector = ({
items,
onSelect,
}: CredentialSelectorProps) => {
const { t } = useTranslation()
const currentCredential = items.find(item => item.credentialId === value)!
const getDisplayName = (item: NotionCredential) => {
return item.workspaceName || t('datasetPipeline.credentialSelector.name', {
credentialName: item.credentialName,
pluginName: 'Notion',
})
return item.workspaceName || item.credentialName
}
const currentDisplayName = useMemo(() => {
@ -43,10 +38,11 @@ const CredentialSelector = ({
({ open }) => (
<>
<MenuButton className={`flex h-7 items-center justify-center rounded-md p-1 pr-2 hover:bg-state-base-hover ${open && 'bg-state-base-hover'} cursor-pointer`}>
<NotionIcon
<CredentialIcon
className='mr-2'
src={currentCredential?.workspaceIcon}
avatarUrl={currentCredential?.workspaceIcon}
name={currentDisplayName}
size={20}
/>
<div
className='mr-1 w-[90px] truncate text-left text-sm font-medium text-text-secondary'
@ -80,10 +76,11 @@ const CredentialSelector = ({
className='flex h-9 cursor-pointer items-center rounded-lg px-3 hover:bg-state-base-hover'
onClick={() => onSelect(item.credentialId)}
>
<NotionIcon
<CredentialIcon
className='mr-2 shrink-0'
src={item.workspaceIcon}
avatarUrl={item.workspaceIcon}
name={displayName}
size={20}
/>
<div
className='system-sm-medium mr-2 grow truncate text-text-secondary'

View File

@ -7,6 +7,7 @@ import Checkbox from '../../checkbox'
import NotionIcon from '../../notion-icon'
import cn from '@/utils/classnames'
import type { DataSourceNotionPage, DataSourceNotionPageMap } from '@/models/common'
import Radio from '@/app/components/base/radio/ui'
type PageSelectorProps = {
value: Set<string>
@ -18,6 +19,7 @@ type PageSelectorProps = {
canPreview?: boolean
previewPageId?: string
onPreview?: (selectedPageId: string) => void
isMultipleChoice?: boolean
}
type NotionPageTreeItem = {
children: Set<string>
@ -80,6 +82,7 @@ const ItemComponent = ({ index, style, data }: ListChildComponentProps<{
searchValue: string
previewPageId: string
pagesMap: DataSourceNotionPageMap
isMultipleChoice?: boolean
}>) => {
const { t } = useTranslation()
const {
@ -94,6 +97,7 @@ const ItemComponent = ({ index, style, data }: ListChildComponentProps<{
searchValue,
previewPageId,
pagesMap,
isMultipleChoice,
} = data
const current = dataList[index]
const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[current.page_id]
@ -134,16 +138,24 @@ const ItemComponent = ({ index, style, data }: ListChildComponentProps<{
previewPageId === current.page_id && 'bg-state-base-hover')}
style={{ ...style, top: style.top as number + 8, left: 8, right: 8, width: 'calc(100% - 16px)' }}
>
<Checkbox
className='mr-2 shrink-0'
checked={checkedIds.has(current.page_id)}
disabled={disabled}
onCheck={() => {
if (disabled)
return
handleCheck(index)
}}
/>
{isMultipleChoice ? (
<Checkbox
className='mr-2 shrink-0'
checked={checkedIds.has(current.page_id)}
disabled={disabled}
onCheck={() => {
handleCheck(index)
}}
/>) : (
<Radio
className='mr-2 shrink-0'
isChecked={checkedIds.has(current.page_id)}
disabled={disabled}
onCheck={() => {
handleCheck(index)
}}
/>
)}
{!searchValue && renderArrow()}
<NotionIcon
className='mr-1 shrink-0'
@ -192,6 +204,7 @@ const PageSelector = ({
canPreview = true,
previewPageId,
onPreview,
isMultipleChoice = true,
}: PageSelectorProps) => {
const { t } = useTranslation()
const [dataList, setDataList] = useState<NotionPageItem[]>([])
@ -265,7 +278,7 @@ const PageSelector = ({
const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[pageId]
if (copyValue.has(pageId)) {
if (!searchValue) {
if (!searchValue && isMultipleChoice) {
for (const item of currentWithChildrenAndDescendants.descendants)
copyValue.delete(item)
}
@ -273,12 +286,18 @@ const PageSelector = ({
copyValue.delete(pageId)
}
else {
if (!searchValue) {
if (!searchValue && isMultipleChoice) {
for (const item of currentWithChildrenAndDescendants.descendants)
copyValue.add(item)
}
copyValue.add(pageId)
// Single choice mode, clear previous selection
if (!isMultipleChoice && copyValue.size > 0) {
copyValue.clear()
copyValue.add(pageId)
}
else {
copyValue.add(pageId)
}
}
onSelect(new Set(copyValue))
@ -322,6 +341,7 @@ const PageSelector = ({
searchValue,
previewPageId: currentPreviewPageId,
pagesMap,
isMultipleChoice,
}}
>
{Item}

View File

@ -2,7 +2,7 @@ import cn from '@/utils/classnames'
import React, { useCallback, useMemo, useState } from 'react'
type CredentialIconProps = {
avatar_url?: string
avatarUrl?: string
name: string
size?: number
className?: string
@ -16,12 +16,12 @@ const ICON_BG_COLORS = [
]
export const CredentialIcon: React.FC<CredentialIconProps> = ({
avatar_url,
avatarUrl,
name,
size = 20,
className = '',
}) => {
const [showAvatar, setShowAvatar] = useState(!!avatar_url && avatar_url !== 'default')
const [showAvatar, setShowAvatar] = useState(!!avatarUrl && avatarUrl !== 'default')
const firstLetter = useMemo(() => name.charAt(0).toUpperCase(), [name])
const bgColor = useMemo(() => ICON_BG_COLORS[firstLetter.charCodeAt(0) % ICON_BG_COLORS.length], [firstLetter])
@ -29,17 +29,20 @@ export const CredentialIcon: React.FC<CredentialIconProps> = ({
setShowAvatar(false)
}, [])
if (avatar_url && avatar_url !== 'default' && showAvatar) {
if (avatarUrl && avatarUrl !== 'default' && showAvatar) {
return (
<div
className='flex shrink-0 items-center justify-center overflow-hidden rounded-md border border-divider-regular'
className={cn(
'flex shrink-0 items-center justify-center overflow-hidden rounded-md border border-divider-regular',
className,
)}
style={{ width: `${size}px`, height: `${size}px` }}
>
<img
src={avatar_url}
src={avatarUrl}
width={size}
height={size}
className={cn('shrink-0 object-contain', className)}
className='shrink-0 object-contain'
onError={onImgLoadError}
/>
</div>

View File

@ -25,7 +25,7 @@ type IFileUploaderProps = {
onFileUpdate: (fileItem: FileItem, progress: number, list: FileItem[]) => void
onFileListUpdate?: (files: FileItem[]) => void
onPreview: (file: File) => void
notSupportBatchUpload?: boolean
supportBatchUpload?: boolean
}
const FileUploader = ({
@ -35,7 +35,7 @@ const FileUploader = ({
onFileUpdate,
onFileListUpdate,
onPreview,
notSupportBatchUpload,
supportBatchUpload = false,
}: IFileUploaderProps) => {
const { t } = useTranslation()
const { notify } = useContext(ToastContext)
@ -44,7 +44,7 @@ const FileUploader = ({
const dropRef = useRef<HTMLDivElement>(null)
const dragRef = useRef<HTMLDivElement>(null)
const fileUploader = useRef<HTMLInputElement>(null)
const hideUpload = notSupportBatchUpload && fileList.length > 0
const hideUpload = !supportBatchUpload && fileList.length > 0
const { data: fileUploadConfigResponse } = useFileUploadConfig()
const { data: supportFileTypesResponse } = useFileSupportTypes()
@ -68,9 +68,9 @@ const FileUploader = ({
const ACCEPTS = supportTypes.map((ext: string) => `.${ext}`)
const fileUploadConfig = useMemo(() => ({
file_size_limit: fileUploadConfigResponse?.file_size_limit ?? 15,
batch_count_limit: fileUploadConfigResponse?.batch_count_limit ?? 5,
file_upload_limit: fileUploadConfigResponse?.file_upload_limit ?? 5,
}), [fileUploadConfigResponse])
batch_count_limit: supportBatchUpload ? (fileUploadConfigResponse?.batch_count_limit ?? 5) : 1,
file_upload_limit: supportBatchUpload ? (fileUploadConfigResponse?.file_upload_limit ?? 5) : 1,
}), [fileUploadConfigResponse, supportBatchUpload])
const fileListRef = useRef<FileItem[]>([])
@ -254,12 +254,12 @@ const FileUploader = ({
}),
)
let files = nested.flat()
if (notSupportBatchUpload) files = files.slice(0, 1)
if (!supportBatchUpload) files = files.slice(0, 1)
files = files.slice(0, fileUploadConfig.batch_count_limit)
const valid = files.filter(isValid)
initialUpload(valid)
},
[initialUpload, isValid, notSupportBatchUpload, traverseFileEntry, fileUploadConfig],
[initialUpload, isValid, supportBatchUpload, traverseFileEntry, fileUploadConfig],
)
const selectHandle = () => {
if (fileUploader.current)
@ -303,7 +303,7 @@ const FileUploader = ({
id="fileUploader"
className="hidden"
type="file"
multiple={!notSupportBatchUpload}
multiple={supportBatchUpload}
accept={ACCEPTS.join(',')}
onChange={fileChangeHandle}
/>
@ -317,7 +317,7 @@ const FileUploader = ({
<RiUploadCloud2Line className='mr-2 size-5' />
<span>
{notSupportBatchUpload ? t('datasetCreation.stepOne.uploader.buttonSingleFile') : t('datasetCreation.stepOne.uploader.button')}
{supportBatchUpload ? t('datasetCreation.stepOne.uploader.button') : t('datasetCreation.stepOne.uploader.buttonSingleFile')}
{supportTypes.length > 0 && (
<label className="ml-1 cursor-pointer text-text-accent" onClick={selectHandle}>{t('datasetCreation.stepOne.uploader.browse')}</label>
)}
@ -326,7 +326,7 @@ const FileUploader = ({
<div>{t('datasetCreation.stepOne.uploader.tip', {
size: fileUploadConfig.file_size_limit,
supportTypes: supportTypesShowNames,
batchCount: notSupportBatchUpload ? 1 : fileUploadConfig.batch_count_limit,
batchCount: fileUploadConfig.batch_count_limit,
totalCount: fileUploadConfig.file_upload_limit,
})}</div>
{dragging && <div ref={dragRef} className='absolute left-0 top-0 h-full w-full' />}

View File

@ -110,7 +110,7 @@ const StepOne = ({
const hasNotin = notionPages.length > 0
const isVectorSpaceFull = plan.usage.vectorSpace >= plan.total.vectorSpace
const isShowVectorSpaceFull = (allFileLoaded || hasNotin) && isVectorSpaceFull && enableBilling
const notSupportBatchUpload = enableBilling && plan.type === 'sandbox'
const supportBatchUpload = !enableBilling || plan.type !== 'sandbox'
const nextDisabled = useMemo(() => {
if (!files.length)
return true
@ -229,7 +229,7 @@ const StepOne = ({
onFileListUpdate={updateFileList}
onFileUpdate={updateFile}
onPreview={updateCurrentFile}
notSupportBatchUpload={notSupportBatchUpload}
supportBatchUpload={supportBatchUpload}
/>
{isShowVectorSpaceFull && (
<div className='mb-4 max-w-[640px]'>
@ -259,6 +259,7 @@ const StepOne = ({
credentialList={notionCredentialList}
onSelectCredential={updateNotionCredentialId}
datasetId={datasetId}
supportBatchUpload={supportBatchUpload}
/>
</div>
{isShowVectorSpaceFull && (

View File

@ -6,6 +6,7 @@ import cn from '@/utils/classnames'
import type { CrawlResultItem as CrawlResultItemType } from '@/models/datasets'
import Checkbox from '@/app/components/base/checkbox'
import Button from '@/app/components/base/button'
import Radio from '@/app/components/base/radio/ui'
type Props = {
payload: CrawlResultItemType
@ -13,6 +14,7 @@ type Props = {
isPreview: boolean
onCheckChange: (checked: boolean) => void
onPreview: () => void
isMultipleChoice: boolean
}
const CrawledResultItem: FC<Props> = ({
@ -21,6 +23,7 @@ const CrawledResultItem: FC<Props> = ({
isChecked,
onCheckChange,
onPreview,
isMultipleChoice,
}) => {
const { t } = useTranslation()
@ -31,7 +34,21 @@ const CrawledResultItem: FC<Props> = ({
<div className={cn(isPreview ? 'bg-state-base-active' : 'group hover:bg-state-base-hover', 'cursor-pointer rounded-lg p-2')}>
<div className='relative flex'>
<div className='flex h-5 items-center'>
<Checkbox className='mr-2 shrink-0' checked={isChecked} onCheck={handleCheckChange} />
{
isMultipleChoice ? (
<Checkbox
className='mr-2 shrink-0'
checked={isChecked}
onCheck={handleCheckChange}
/>
) : (
<Radio
className='mr-2 shrink-0'
isChecked={isChecked}
onCheck={handleCheckChange}
/>
)
}
</div>
<div className='flex min-w-0 grow flex-col'>
<div

View File

@ -16,6 +16,7 @@ type Props = {
onSelectedChange: (selected: CrawlResultItem[]) => void
onPreview: (payload: CrawlResultItem) => void
usedTime: number
isMultipleChoice: boolean
}
const CrawledResult: FC<Props> = ({
@ -25,6 +26,7 @@ const CrawledResult: FC<Props> = ({
onSelectedChange,
onPreview,
usedTime,
isMultipleChoice,
}) => {
const { t } = useTranslation()
@ -40,13 +42,17 @@ const CrawledResult: FC<Props> = ({
const handleItemCheckChange = useCallback((item: CrawlResultItem) => {
return (checked: boolean) => {
if (checked)
onSelectedChange([...checkedList, item])
else
if (checked) {
if (isMultipleChoice)
onSelectedChange([...checkedList, item])
else
onSelectedChange([item])
}
else {
onSelectedChange(checkedList.filter(checkedItem => checkedItem.source_url !== item.source_url))
}
}
}, [checkedList, onSelectedChange])
}, [checkedList, isMultipleChoice, onSelectedChange])
const [previewIndex, setPreviewIndex] = React.useState<number>(-1)
const handlePreview = useCallback((index: number) => {
@ -59,11 +65,13 @@ const CrawledResult: FC<Props> = ({
return (
<div className={cn(className, 'border-t-[0.5px] border-divider-regular shadow-xs shadow-shadow-shadow-3')}>
<div className='flex h-[34px] items-center justify-between px-4'>
<CheckboxWithLabel
isChecked={isCheckAll}
onChange={handleCheckedAll} label={isCheckAll ? t(`${I18N_PREFIX}.resetAll`) : t(`${I18N_PREFIX}.selectAll`)}
labelClassName='system-[13px] leading-[16px] font-medium text-text-secondary'
/>
{isMultipleChoice && (
<CheckboxWithLabel
isChecked={isCheckAll}
onChange={handleCheckedAll} label={isCheckAll ? t(`${I18N_PREFIX}.resetAll`) : t(`${I18N_PREFIX}.selectAll`)}
labelClassName='system-[13px] leading-[16px] font-medium text-text-secondary'
/>
)}
<div className='text-xs text-text-tertiary'>
{t(`${I18N_PREFIX}.scrapTimeInfo`, {
total: list.length,
@ -80,6 +88,7 @@ const CrawledResult: FC<Props> = ({
payload={item}
isChecked={checkedList.some(checkedItem => checkedItem.source_url === item.source_url)}
onCheckChange={handleItemCheckChange(item)}
isMultipleChoice={isMultipleChoice}
/>
))}
</div>

View File

@ -26,6 +26,7 @@ type Props = {
onJobIdChange: (jobId: string) => void
crawlOptions: CrawlOptions
onCrawlOptionsChange: (payload: CrawlOptions) => void
supportBatchUpload: boolean
}
enum Step {
@ -41,6 +42,7 @@ const FireCrawl: FC<Props> = ({
onJobIdChange,
crawlOptions,
onCrawlOptionsChange,
supportBatchUpload,
}) => {
const { t } = useTranslation()
const [step, setStep] = useState<Step>(Step.init)
@ -171,7 +173,7 @@ const FireCrawl: FC<Props> = ({
content: item.markdown,
}))
setCrawlResult(data)
onCheckedCrawlResultChange(data.data || []) // default select the crawl result
onCheckedCrawlResultChange(supportBatchUpload ? (data.data || []) : (data.data?.slice(0, 1) || [])) // default select the crawl result
setCrawlErrorMessage('')
}
}
@ -182,7 +184,7 @@ const FireCrawl: FC<Props> = ({
finally {
setStep(Step.finished)
}
}, [checkValid, crawlOptions, onJobIdChange, t, waitForCrawlFinished, onCheckedCrawlResultChange])
}, [checkValid, crawlOptions, onJobIdChange, waitForCrawlFinished, t, onCheckedCrawlResultChange, supportBatchUpload])
return (
<div>
@ -221,6 +223,7 @@ const FireCrawl: FC<Props> = ({
onSelectedChange={onCheckedCrawlResultChange}
onPreview={onPreview}
usedTime={Number.parseFloat(crawlResult?.time_consuming as string) || 0}
isMultipleChoice={supportBatchUpload}
/>
}
</div>

View File

@ -24,6 +24,7 @@ type Props = {
crawlOptions: CrawlOptions
onCrawlOptionsChange: (payload: CrawlOptions) => void
authedDataSourceList: DataSourceAuth[]
supportBatchUpload?: boolean
}
const Website: FC<Props> = ({
@ -35,6 +36,7 @@ const Website: FC<Props> = ({
crawlOptions,
onCrawlOptionsChange,
authedDataSourceList,
supportBatchUpload = false,
}) => {
const { t } = useTranslation()
const { setShowAccountSettingModal } = useModalContext()
@ -116,6 +118,7 @@ const Website: FC<Props> = ({
onJobIdChange={onJobIdChange}
crawlOptions={crawlOptions}
onCrawlOptionsChange={onCrawlOptionsChange}
supportBatchUpload={supportBatchUpload}
/>
)}
{source && selectedProvider === DataSourceProvider.waterCrawl && (
@ -126,6 +129,7 @@ const Website: FC<Props> = ({
onJobIdChange={onJobIdChange}
crawlOptions={crawlOptions}
onCrawlOptionsChange={onCrawlOptionsChange}
supportBatchUpload={supportBatchUpload}
/>
)}
{source && selectedProvider === DataSourceProvider.jinaReader && (
@ -136,6 +140,7 @@ const Website: FC<Props> = ({
onJobIdChange={onJobIdChange}
crawlOptions={crawlOptions}
onCrawlOptionsChange={onCrawlOptionsChange}
supportBatchUpload={supportBatchUpload}
/>
)}
{!source && (

View File

@ -26,6 +26,7 @@ type Props = {
onJobIdChange: (jobId: string) => void
crawlOptions: CrawlOptions
onCrawlOptionsChange: (payload: CrawlOptions) => void
supportBatchUpload: boolean
}
enum Step {
@ -41,6 +42,7 @@ const JinaReader: FC<Props> = ({
onJobIdChange,
crawlOptions,
onCrawlOptionsChange,
supportBatchUpload,
}) => {
const { t } = useTranslation()
const [step, setStep] = useState<Step>(Step.init)
@ -157,7 +159,7 @@ const JinaReader: FC<Props> = ({
total: 1,
data: [{
title,
content,
markdown: content,
description,
source_url: url,
}],
@ -176,7 +178,7 @@ const JinaReader: FC<Props> = ({
}
else {
setCrawlResult(data)
onCheckedCrawlResultChange(data.data || []) // default select the crawl result
onCheckedCrawlResultChange(supportBatchUpload ? (data.data || []) : (data.data?.slice(0, 1) || [])) // default select the crawl result
setCrawlErrorMessage('')
}
}
@ -188,7 +190,7 @@ const JinaReader: FC<Props> = ({
finally {
setStep(Step.finished)
}
}, [checkValid, crawlOptions, onCheckedCrawlResultChange, onJobIdChange, t, waitForCrawlFinished])
}, [checkValid, crawlOptions, onCheckedCrawlResultChange, onJobIdChange, supportBatchUpload, t, waitForCrawlFinished])
return (
<div>
@ -227,6 +229,7 @@ const JinaReader: FC<Props> = ({
onSelectedChange={onCheckedCrawlResultChange}
onPreview={onPreview}
usedTime={Number.parseFloat(crawlResult?.time_consuming as string) || 0}
isMultipleChoice={supportBatchUpload}
/>
}
</div>

View File

@ -32,7 +32,7 @@ const WebsitePreview = ({
<div className='system-xs-medium truncate text-text-tertiary' title={payload.source_url}>{payload.source_url}</div>
</div>
<div className={cn(s.previewContent, 'body-md-regular')}>
<div className={cn(s.fileContent)}>{payload.content}</div>
<div className={cn(s.fileContent)}>{payload.markdown}</div>
</div>
</div>
)

View File

@ -26,6 +26,7 @@ type Props = {
onJobIdChange: (jobId: string) => void
crawlOptions: CrawlOptions
onCrawlOptionsChange: (payload: CrawlOptions) => void
supportBatchUpload: boolean
}
enum Step {
@ -41,6 +42,7 @@ const WaterCrawl: FC<Props> = ({
onJobIdChange,
crawlOptions,
onCrawlOptionsChange,
supportBatchUpload,
}) => {
const { t } = useTranslation()
const [step, setStep] = useState<Step>(Step.init)
@ -132,7 +134,7 @@ const WaterCrawl: FC<Props> = ({
},
}
}
}, [crawlOptions.limit])
}, [crawlOptions.limit, onCheckedCrawlResultChange])
const handleRun = useCallback(async (url: string) => {
const { isValid, errorMsg } = checkValid(url)
@ -163,7 +165,7 @@ const WaterCrawl: FC<Props> = ({
}
else {
setCrawlResult(data)
onCheckedCrawlResultChange(data.data || []) // default select the crawl result
onCheckedCrawlResultChange(supportBatchUpload ? (data.data || []) : (data.data?.slice(0, 1) || [])) // default select the crawl result
setCrawlErrorMessage('')
}
}
@ -174,7 +176,7 @@ const WaterCrawl: FC<Props> = ({
finally {
setStep(Step.finished)
}
}, [checkValid, crawlOptions, onJobIdChange, t, waitForCrawlFinished])
}, [checkValid, crawlOptions, onCheckedCrawlResultChange, onJobIdChange, supportBatchUpload, t, waitForCrawlFinished])
return (
<div>
@ -213,6 +215,7 @@ const WaterCrawl: FC<Props> = ({
onSelectedChange={onCheckedCrawlResultChange}
onPreview={onPreview}
usedTime={Number.parseFloat(crawlResult?.time_consuming as string) || 0}
isMultipleChoice={supportBatchUpload}
/>
}
</div>

View File

@ -10,14 +10,12 @@ import Trigger from './trigger'
import List from './list'
export type CredentialSelectorProps = {
pluginName: string
currentCredentialId: string
onCredentialChange: (credentialId: string) => void
credentials: Array<DataSourceCredential>
}
const CredentialSelector = ({
pluginName,
currentCredentialId,
onCredentialChange,
credentials,
@ -50,7 +48,6 @@ const CredentialSelector = ({
<PortalToFollowElemTrigger onClick={toggle} className='grow overflow-hidden'>
<Trigger
currentCredential={currentCredential}
pluginName={pluginName}
isOpen={open}
/>
</PortalToFollowElemTrigger>
@ -58,7 +55,6 @@ const CredentialSelector = ({
<List
currentCredentialId={currentCredentialId}
credentials={credentials}
pluginName={pluginName}
onCredentialChange={handleCredentialChange}
/>
</PortalToFollowElemContent>

View File

@ -2,22 +2,18 @@ import { CredentialIcon } from '@/app/components/datasets/common/credential-icon
import type { DataSourceCredential } from '@/types/pipeline'
import { RiCheckLine } from '@remixicon/react'
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
type ItemProps = {
credential: DataSourceCredential
pluginName: string
isSelected: boolean
onCredentialChange: (credentialId: string) => void
}
const Item = ({
credential,
pluginName,
isSelected,
onCredentialChange,
}: ItemProps) => {
const { t } = useTranslation()
const { avatar_url, name } = credential
const handleCredentialChange = useCallback(() => {
@ -30,15 +26,12 @@ const Item = ({
onClick={handleCredentialChange}
>
<CredentialIcon
avatar_url={avatar_url}
avatarUrl={avatar_url}
name={name}
size={20}
/>
<span className='system-sm-medium grow truncate text-text-secondary'>
{t('datasetPipeline.credentialSelector.name', {
credentialName: name,
pluginName,
})}
{name}
</span>
{
isSelected && (

View File

@ -5,14 +5,12 @@ import Item from './item'
type ListProps = {
currentCredentialId: string
credentials: Array<DataSourceCredential>
pluginName: string
onCredentialChange: (credentialId: string) => void
}
const List = ({
currentCredentialId,
credentials,
pluginName,
onCredentialChange,
}: ListProps) => {
return (
@ -24,7 +22,6 @@ const List = ({
<Item
key={credential.id}
credential={credential}
pluginName={pluginName}
isSelected={isSelected}
onCredentialChange={onCredentialChange}
/>

View File

@ -1,23 +1,18 @@
import React from 'react'
import type { DataSourceCredential } from '@/types/pipeline'
import { useTranslation } from 'react-i18next'
import { RiArrowDownSLine } from '@remixicon/react'
import cn from '@/utils/classnames'
import { CredentialIcon } from '@/app/components/datasets/common/credential-icon'
type TriggerProps = {
currentCredential: DataSourceCredential | undefined
pluginName: string
isOpen: boolean
}
const Trigger = ({
currentCredential,
pluginName,
isOpen,
}: TriggerProps) => {
const { t } = useTranslation()
const {
avatar_url,
name = '',
@ -31,16 +26,13 @@ const Trigger = ({
)}
>
<CredentialIcon
avatar_url={avatar_url}
avatarUrl={avatar_url}
name={name}
size={20}
/>
<div className='flex grow items-center gap-x-1 overflow-hidden'>
<span className='system-md-semibold grow truncate text-text-secondary'>
{t('datasetPipeline.credentialSelector.name', {
credentialName: name,
pluginName,
})}
{name}
</span>
<RiArrowDownSLine className='size-4 shrink-0 text-text-secondary' />
</div>

View File

@ -11,12 +11,14 @@ type HeaderProps = {
docTitle: string
docLink: string
onClickConfiguration?: () => void
pluginName: string
} & CredentialSelectorProps
const Header = ({
docTitle,
docLink,
onClickConfiguration,
pluginName,
...rest
}: HeaderProps) => {
const { t } = useTranslation()
@ -29,7 +31,7 @@ const Header = ({
/>
<Divider type='vertical' className='mx-1 h-3.5 shrink-0' />
<Tooltip
popupContent={t('datasetPipeline.configurationTip', { pluginName: rest.pluginName })}
popupContent={t('datasetPipeline.configurationTip', { pluginName })}
position='top'
>
<Button

View File

@ -23,12 +23,12 @@ const SimplePieChart = dynamic(() => import('@/app/components/base/simple-pie-ch
export type LocalFileProps = {
allowedExtensions: string[]
notSupportBatchUpload?: boolean
supportBatchUpload?: boolean
}
const LocalFile = ({
allowedExtensions,
notSupportBatchUpload,
supportBatchUpload = false,
}: LocalFileProps) => {
const { t } = useTranslation()
const { notify } = useContext(ToastContext)
@ -42,7 +42,7 @@ const LocalFile = ({
const fileUploader = useRef<HTMLInputElement>(null)
const fileListRef = useRef<FileItem[]>([])
const hideUpload = notSupportBatchUpload && localFileList.length > 0
const hideUpload = !supportBatchUpload && localFileList.length > 0
const { data: fileUploadConfigResponse } = useFileUploadConfig()
const supportTypesShowNames = useMemo(() => {
@ -64,9 +64,9 @@ const LocalFile = ({
const ACCEPTS = allowedExtensions.map((ext: string) => `.${ext}`)
const fileUploadConfig = useMemo(() => ({
file_size_limit: fileUploadConfigResponse?.file_size_limit ?? 15,
batch_count_limit: fileUploadConfigResponse?.batch_count_limit ?? 5,
file_upload_limit: fileUploadConfigResponse?.file_upload_limit ?? 5,
}), [fileUploadConfigResponse])
batch_count_limit: supportBatchUpload ? (fileUploadConfigResponse?.batch_count_limit ?? 5) : 1,
file_upload_limit: supportBatchUpload ? (fileUploadConfigResponse?.file_upload_limit ?? 5) : 1,
}), [fileUploadConfigResponse, supportBatchUpload])
const updateFile = useCallback((fileItem: FileItem, progress: number, list: FileItem[]) => {
const { setLocalFileList } = dataSourceStore.getState()
@ -119,7 +119,7 @@ const LocalFile = ({
notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.size', { size: fileUploadConfig.file_size_limit }) })
return isValidType && isValidSize
}, [fileUploadConfig, notify, t, ACCEPTS])
}, [notify, t, ACCEPTS, fileUploadConfig.file_size_limit])
type UploadResult = Awaited<ReturnType<typeof upload>>
@ -230,12 +230,12 @@ const LocalFile = ({
return
let files = [...e.dataTransfer.files] as File[]
if (notSupportBatchUpload)
if (!supportBatchUpload)
files = files.slice(0, 1)
const validFiles = files.filter(isValid)
initialUpload(validFiles)
}, [initialUpload, isValid, notSupportBatchUpload])
}, [initialUpload, isValid, supportBatchUpload])
const selectHandle = useCallback(() => {
if (fileUploader.current)
@ -280,7 +280,7 @@ const LocalFile = ({
id='fileUploader'
className='hidden'
type='file'
multiple={!notSupportBatchUpload}
multiple={supportBatchUpload}
accept={ACCEPTS.join(',')}
onChange={fileChangeHandle}
/>
@ -296,7 +296,7 @@ const LocalFile = ({
<RiUploadCloud2Line className='mr-2 size-5' />
<span>
{notSupportBatchUpload ? t('datasetCreation.stepOne.uploader.buttonSingleFile') : t('datasetCreation.stepOne.uploader.button')}
{supportBatchUpload ? t('datasetCreation.stepOne.uploader.button') : t('datasetCreation.stepOne.uploader.buttonSingleFile')}
{allowedExtensions.length > 0 && (
<label className='ml-1 cursor-pointer text-text-accent' onClick={selectHandle}>{t('datasetCreation.stepOne.uploader.browse')}</label>
)}
@ -305,7 +305,7 @@ const LocalFile = ({
<div>{t('datasetCreation.stepOne.uploader.tip', {
size: fileUploadConfig.file_size_limit,
supportTypes: supportTypesShowNames,
batchCount: notSupportBatchUpload ? 1 : fileUploadConfig.batch_count_limit,
batchCount: fileUploadConfig.batch_count_limit,
totalCount: fileUploadConfig.file_upload_limit,
})}</div>
{dragging && <div ref={dragRef} className='absolute left-0 top-0 h-full w-full' />}

View File

@ -19,16 +19,18 @@ import { useDocLink } from '@/context/i18n'
import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/constants'
type OnlineDocumentsProps = {
isInPipeline?: boolean
nodeId: string
nodeData: DataSourceNodeType
onCredentialChange: (credentialId: string) => void
isInPipeline?: boolean
supportBatchUpload?: boolean
}
const OnlineDocuments = ({
nodeId,
nodeData,
isInPipeline = false,
supportBatchUpload = false,
onCredentialChange,
}: OnlineDocumentsProps) => {
const docLink = useDocLink()
@ -157,7 +159,7 @@ const OnlineDocuments = ({
onSelect={handleSelectPages}
canPreview={!isInPipeline}
onPreview={handlePreviewPage}
isMultipleChoice={!isInPipeline}
isMultipleChoice={supportBatchUpload}
currentCredentialId={currentCredentialId}
/>
) : (

View File

@ -17,6 +17,7 @@ type FileListProps = {
handleSelectFile: (file: OnlineDriveFile) => void
handleOpenFolder: (file: OnlineDriveFile) => void
isLoading: boolean
supportBatchUpload: boolean
}
const FileList = ({
@ -32,6 +33,7 @@ const FileList = ({
handleOpenFolder,
isInPipeline,
isLoading,
supportBatchUpload,
}: FileListProps) => {
const [inputValue, setInputValue] = useState(keywords)
@ -72,8 +74,8 @@ const FileList = ({
handleResetKeywords={handleResetKeywords}
handleOpenFolder={handleOpenFolder}
handleSelectFile={handleSelectFile}
isInPipeline={isInPipeline}
isLoading={isLoading}
supportBatchUpload={supportBatchUpload}
/>
</div>
)

View File

@ -11,8 +11,8 @@ type FileListProps = {
fileList: OnlineDriveFile[]
selectedFileIds: string[]
keywords: string
isInPipeline: boolean
isLoading: boolean
supportBatchUpload: boolean
handleResetKeywords: () => void
handleSelectFile: (file: OnlineDriveFile) => void
handleOpenFolder: (file: OnlineDriveFile) => void
@ -25,8 +25,8 @@ const List = ({
handleResetKeywords,
handleSelectFile,
handleOpenFolder,
isInPipeline,
isLoading,
supportBatchUpload,
}: FileListProps) => {
const anchorRef = useRef<HTMLDivElement>(null)
const observerRef = useRef<IntersectionObserver>(null)
@ -80,7 +80,7 @@ const List = ({
isSelected={isSelected}
onSelect={handleSelectFile}
onOpen={handleOpenFolder}
isMultipleChoice={!isInPipeline}
isMultipleChoice={supportBatchUpload}
/>
)
})

View File

@ -20,14 +20,16 @@ import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/con
type OnlineDriveProps = {
nodeId: string
nodeData: DataSourceNodeType
isInPipeline?: boolean
onCredentialChange: (credentialId: string) => void
isInPipeline?: boolean
supportBatchUpload?: boolean
}
const OnlineDrive = ({
nodeId,
nodeData,
isInPipeline = false,
supportBatchUpload = false,
onCredentialChange,
}: OnlineDriveProps) => {
const docLink = useDocLink()
@ -111,7 +113,7 @@ const OnlineDrive = ({
},
},
)
}, [datasourceNodeRunURL, dataSourceStore])
}, [dataSourceStore, datasourceNodeRunURL, breadcrumbs])
useEffect(() => {
if (!currentCredentialId) return
@ -152,12 +154,12 @@ const OnlineDrive = ({
draft.splice(index, 1)
}
else {
if (isInPipeline && draft.length >= 1) return
if (!supportBatchUpload && draft.length >= 1) return
draft.push(file.id)
}
})
setSelectedFileIds(newSelectedFileList)
}, [dataSourceStore, isInPipeline])
}, [dataSourceStore, supportBatchUpload])
const handleOpenFolder = useCallback((file: OnlineDriveFile) => {
const { breadcrumbs, prefix, setBreadcrumbs, setPrefix, setBucket, setOnlineDriveFileList, setSelectedFileIds } = dataSourceStore.getState()
@ -177,7 +179,7 @@ const OnlineDrive = ({
setBreadcrumbs(newBreadcrumbs)
setPrefix(newPrefix)
}
}, [dataSourceStore, getOnlineDriveFiles])
}, [dataSourceStore])
const handleSetting = useCallback(() => {
setShowAccountSettingModal({
@ -209,6 +211,7 @@ const OnlineDrive = ({
handleOpenFolder={handleOpenFolder}
isInPipeline={isInPipeline}
isLoading={isLoading}
supportBatchUpload={supportBatchUpload}
/>
</div>
)

View File

@ -46,6 +46,7 @@ const CrawledResultItem = ({
/>
) : (
<Radio
className='shrink-0'
isChecked={isChecked}
onCheck={handleCheckChange}
/>

View File

@ -33,14 +33,16 @@ const I18N_PREFIX = 'datasetCreation.stepOne.website'
export type WebsiteCrawlProps = {
nodeId: string
nodeData: DataSourceNodeType
isInPipeline?: boolean
onCredentialChange: (credentialId: string) => void
isInPipeline?: boolean
supportBatchUpload?: boolean
}
const WebsiteCrawl = ({
nodeId,
nodeData,
isInPipeline = false,
supportBatchUpload = false,
onCredentialChange,
}: WebsiteCrawlProps) => {
const { t } = useTranslation()
@ -122,7 +124,7 @@ const WebsiteCrawl = ({
time_consuming: time_consuming ?? 0,
}
setCrawlResult(crawlResultData)
handleCheckedCrawlResultChange(isInPipeline ? [crawlData[0]] : crawlData) // default select the crawl result
handleCheckedCrawlResultChange(supportBatchUpload ? crawlData : crawlData.slice(0, 1)) // default select the crawl result
setCrawlErrorMessage('')
setStep(CrawlStep.finished)
},
@ -132,7 +134,7 @@ const WebsiteCrawl = ({
},
},
)
}, [dataSourceStore, datasourceNodeRunURL, handleCheckedCrawlResultChange, isInPipeline, t])
}, [dataSourceStore, datasourceNodeRunURL, handleCheckedCrawlResultChange, supportBatchUpload, t])
const handleSubmit = useCallback((value: Record<string, any>) => {
handleRun(value)
@ -149,7 +151,7 @@ const WebsiteCrawl = ({
setTotalNum(0)
setCrawlErrorMessage('')
onCredentialChange(credentialId)
}, [dataSourceStore, onCredentialChange])
}, [onCredentialChange])
return (
<div className='flex flex-col'>
@ -195,7 +197,7 @@ const WebsiteCrawl = ({
previewIndex={previewIndex}
onPreview={handlePreview}
showPreview={!isInPipeline}
isMultipleChoice={!isInPipeline} // only support single choice in test run
isMultipleChoice={supportBatchUpload} // only support single choice in test run
/>
)}
</div>

View File

@ -102,7 +102,7 @@ const CreateFormPipeline = () => {
return onlineDriveFileList.length > 0 && isVectorSpaceFull && enableBilling
return false
}, [allFileLoaded, datasource, datasourceType, enableBilling, isVectorSpaceFull, onlineDocuments.length, onlineDriveFileList.length, websitePages.length])
const notSupportBatchUpload = enableBilling && plan.type === 'sandbox'
const supportBatchUpload = !enableBilling || plan.type !== 'sandbox'
const nextBtnDisabled = useMemo(() => {
if (!datasource) return true
@ -125,15 +125,16 @@ const CreateFormPipeline = () => {
const showSelect = useMemo(() => {
if (datasourceType === DatasourceType.onlineDocument) {
const pagesCount = currentWorkspace?.pages.length ?? 0
return pagesCount > 0
return supportBatchUpload && pagesCount > 0
}
if (datasourceType === DatasourceType.onlineDrive) {
const isBucketList = onlineDriveFileList.some(file => file.type === 'bucket')
return !isBucketList && onlineDriveFileList.filter((item) => {
return supportBatchUpload && !isBucketList && onlineDriveFileList.filter((item) => {
return item.type !== 'bucket'
}).length > 0
}
}, [currentWorkspace?.pages.length, datasourceType, onlineDriveFileList])
return false
}, [currentWorkspace?.pages.length, datasourceType, supportBatchUpload, onlineDriveFileList])
const totalOptions = useMemo(() => {
if (datasourceType === DatasourceType.onlineDocument)
@ -395,7 +396,7 @@ const CreateFormPipeline = () => {
clearWebsiteCrawlData()
else if (dataSource.nodeData.provider_type === DatasourceType.onlineDrive)
clearOnlineDriveData()
}, [])
}, [clearOnlineDocumentData, clearOnlineDriveData, clearWebsiteCrawlData])
const handleSwitchDataSource = useCallback((dataSource: Datasource) => {
const {
@ -406,13 +407,13 @@ const CreateFormPipeline = () => {
setCurrentCredentialId('')
currentNodeIdRef.current = dataSource.nodeId
setDatasource(dataSource)
}, [dataSourceStore])
}, [clearDataSourceData, dataSourceStore])
const handleCredentialChange = useCallback((credentialId: string) => {
const { setCurrentCredentialId } = dataSourceStore.getState()
clearDataSourceData(datasource!)
setCurrentCredentialId(credentialId)
}, [dataSourceStore, datasource])
}, [clearDataSourceData, dataSourceStore, datasource])
if (isFetchingPipelineInfo) {
return (
@ -443,7 +444,7 @@ const CreateFormPipeline = () => {
{datasourceType === DatasourceType.localFile && (
<LocalFile
allowedExtensions={datasource!.nodeData.fileExtensions || []}
notSupportBatchUpload={notSupportBatchUpload}
supportBatchUpload={supportBatchUpload}
/>
)}
{datasourceType === DatasourceType.onlineDocument && (
@ -451,6 +452,7 @@ const CreateFormPipeline = () => {
nodeId={datasource!.nodeId}
nodeData={datasource!.nodeData}
onCredentialChange={handleCredentialChange}
supportBatchUpload={supportBatchUpload}
/>
)}
{datasourceType === DatasourceType.websiteCrawl && (
@ -458,6 +460,7 @@ const CreateFormPipeline = () => {
nodeId={datasource!.nodeId}
nodeData={datasource!.nodeData}
onCredentialChange={handleCredentialChange}
supportBatchUpload={supportBatchUpload}
/>
)}
{datasourceType === DatasourceType.onlineDrive && (
@ -465,6 +468,7 @@ const CreateFormPipeline = () => {
nodeId={datasource!.nodeId}
nodeData={datasource!.nodeData}
onCredentialChange={handleCredentialChange}
supportBatchUpload={supportBatchUpload}
/>
)}
{isShowVectorSpaceFull && (

View File

@ -27,7 +27,7 @@ const WebsitePreview = ({
<span className='uppercase' title={currentWebsite.source_url}>{currentWebsite.source_url}</span>
<span>·</span>
<span>·</span>
<span>{`${formatNumberAbbreviated(currentWebsite.content.length)} ${t('datasetPipeline.addDocuments.characters')}`}</span>
<span>{`${formatNumberAbbreviated(currentWebsite.markdown.length)} ${t('datasetPipeline.addDocuments.characters')}`}</span>
</div>
</div>
<button
@ -39,7 +39,7 @@ const WebsitePreview = ({
</button>
</div>
<div className='body-md-regular grow overflow-hidden px-6 py-5 text-text-secondary'>
{currentWebsite.content}
{currentWebsite.markdown}
</div>
</div>
)

View File

@ -113,7 +113,7 @@ const DocumentSettings = ({ datasetId, documentId }: DocumentSettingsProps) => {
return [{
title: websiteInfo.title,
source_url: websiteInfo.source_url,
content: websiteInfo.content,
markdown: websiteInfo.content,
description: websiteInfo.description,
}]
}, [websiteInfo])

View File

@ -55,7 +55,7 @@ const PipelineSettings = ({
if (lastRunData?.datasource_type === DatasourceType.websiteCrawl) {
const { content, description, source_url, title } = lastRunData.datasource_info
websitePages.push({
content,
markdown: content,
description,
source_url,
title,
@ -135,7 +135,7 @@ const PipelineSettings = ({
push(`/datasets/${datasetId}/documents`)
},
})
}, [datasetId, invalidDocumentDetail, invalidDocumentList, lastRunData, pipelineId, push, runPublishedPipeline])
}, [datasetId, documentId, invalidDocumentDetail, invalidDocumentList, lastRunData, pipelineId, push, runPublishedPipeline])
const onClickProcess = useCallback(() => {
isPreview.current = false

View File

@ -131,7 +131,7 @@ const Preparation = () => {
clearWebsiteCrawlData()
else if (dataSource.nodeData.provider_type === DatasourceType.onlineDrive)
clearOnlineDriveData()
}, [])
}, [clearOnlineDocumentData, clearOnlineDriveData, clearWebsiteCrawlData])
const handleSwitchDataSource = useCallback((dataSource: Datasource) => {
const {
@ -142,13 +142,13 @@ const Preparation = () => {
setCurrentCredentialId('')
currentNodeIdRef.current = dataSource.nodeId
setDatasource(dataSource)
}, [dataSourceStore])
}, [clearDataSourceData, dataSourceStore])
const handleCredentialChange = useCallback((credentialId: string) => {
const { setCurrentCredentialId } = dataSourceStore.getState()
clearDataSourceData(datasource!)
setCurrentCredentialId(credentialId)
}, [dataSourceStore, datasource])
}, [clearDataSourceData, dataSourceStore, datasource])
return (
<>
<StepIndicator steps={steps} currentStep={currentStep} />
@ -164,7 +164,7 @@ const Preparation = () => {
{datasourceType === DatasourceType.localFile && (
<LocalFile
allowedExtensions={datasource!.nodeData.fileExtensions || []}
notSupportBatchUpload // only support single file upload in test run
supportBatchUpload={false} // only support single file upload in test run
/>
)}
{datasourceType === DatasourceType.onlineDocument && (
@ -173,6 +173,7 @@ const Preparation = () => {
nodeData={datasource!.nodeData}
isInPipeline
onCredentialChange={handleCredentialChange}
supportBatchUpload={false}
/>
)}
{datasourceType === DatasourceType.websiteCrawl && (
@ -181,6 +182,7 @@ const Preparation = () => {
nodeData={datasource!.nodeData}
isInPipeline
onCredentialChange={handleCredentialChange}
supportBatchUpload={false}
/>
)}
{datasourceType === DatasourceType.onlineDrive && (
@ -189,6 +191,7 @@ const Preparation = () => {
nodeData={datasource!.nodeData}
isInPipeline
onCredentialChange={handleCredentialChange}
supportBatchUpload={false}
/>
)}
</div>

View File

@ -43,13 +43,13 @@ const BeforeRunForm: FC<CustomRunFormProps> = (props) => {
clearWebsiteCrawlData()
else if (datasourceType === DatasourceType.onlineDrive)
clearOnlineDriveData()
}, [datasourceType])
}, [clearOnlineDocumentData, clearOnlineDriveData, clearWebsiteCrawlData, datasourceType])
const handleCredentialChange = useCallback((credentialId: string) => {
const { setCurrentCredentialId } = dataSourceStore.getState()
clearDataSourceData()
setCurrentCredentialId(credentialId)
}, [dataSourceStore])
}, [clearDataSourceData, dataSourceStore])
return (
<PanelWrap
@ -60,7 +60,7 @@ const BeforeRunForm: FC<CustomRunFormProps> = (props) => {
{datasourceType === DatasourceType.localFile && (
<LocalFile
allowedExtensions={datasourceNodeData.fileExtensions || []}
notSupportBatchUpload
supportBatchUpload={false}
/>
)}
{datasourceType === DatasourceType.onlineDocument && (
@ -69,6 +69,7 @@ const BeforeRunForm: FC<CustomRunFormProps> = (props) => {
nodeData={datasourceNodeData}
isInPipeline
onCredentialChange={handleCredentialChange}
supportBatchUpload={false}
/>
)}
{datasourceType === DatasourceType.websiteCrawl && (
@ -77,6 +78,7 @@ const BeforeRunForm: FC<CustomRunFormProps> = (props) => {
nodeData={datasourceNodeData}
isInPipeline
onCredentialChange={handleCredentialChange}
supportBatchUpload={false}
/>
)}
{datasourceType === DatasourceType.onlineDrive && (
@ -85,6 +87,7 @@ const BeforeRunForm: FC<CustomRunFormProps> = (props) => {
nodeData={datasourceNodeData}
isInPipeline
onCredentialChange={handleCredentialChange}
supportBatchUpload={false}
/>
)}
<div className='flex justify-end gap-x-2'>

View File

@ -145,9 +145,6 @@ const translation = {
emptySearchResult: 'No items were found',
resetKeywords: 'Reset keywords',
},
credentialSelector: {
name: '{{credentialName}}\'s {{pluginName}}',
},
configurationTip: 'Configure {{pluginName}}',
conversion: {
title: 'Convert to Knowledge Pipeline',

View File

@ -137,9 +137,6 @@ const translation = {
emptySearchResult: 'アイテムは見つかりませんでした',
resetKeywords: 'キーワードをリセットする',
},
credentialSelector: {
name: '{{credentialName}}の{{pluginName}}',
},
configurationTip: '{{pluginName}}を設定',
conversion: {
confirm: {

View File

@ -145,9 +145,6 @@ const translation = {
emptySearchResult: '未找到任何项目',
resetKeywords: '重置关键词',
},
credentialSelector: {
name: '{{credentialName}} 的 {{pluginName}}',
},
configurationTip: '配置 {{pluginName}}',
conversion: {
title: '转换为知识流水线',

View File

@ -156,7 +156,7 @@ export type CrawlOptions = {
export type CrawlResultItem = {
title: string
content: string
markdown: string
description: string
source_url: string
}