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
35 changed files with 206 additions and 151 deletions

View File

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

View File

@@ -1,9 +1,8 @@
'use client' 'use client'
import { useTranslation } from 'react-i18next'
import React, { Fragment, useMemo } from 'react' import React, { Fragment, useMemo } from 'react'
import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react' import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
import { RiArrowDownSLine } from '@remixicon/react' import { RiArrowDownSLine } from '@remixicon/react'
import NotionIcon from '../../notion-icon' import { CredentialIcon } from '@/app/components/datasets/common/credential-icon'
export type NotionCredential = { export type NotionCredential = {
credentialId: string credentialId: string
@@ -23,14 +22,10 @@ const CredentialSelector = ({
items, items,
onSelect, onSelect,
}: CredentialSelectorProps) => { }: CredentialSelectorProps) => {
const { t } = useTranslation()
const currentCredential = items.find(item => item.credentialId === value)! const currentCredential = items.find(item => item.credentialId === value)!
const getDisplayName = (item: NotionCredential) => { const getDisplayName = (item: NotionCredential) => {
return item.workspaceName || t('datasetPipeline.credentialSelector.name', { return item.workspaceName || item.credentialName
credentialName: item.credentialName,
pluginName: 'Notion',
})
} }
const currentDisplayName = useMemo(() => { const currentDisplayName = useMemo(() => {
@@ -43,10 +38,11 @@ const CredentialSelector = ({
({ open }) => ( ({ 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`}> <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' className='mr-2'
src={currentCredential?.workspaceIcon} avatarUrl={currentCredential?.workspaceIcon}
name={currentDisplayName} name={currentDisplayName}
size={20}
/> />
<div <div
className='mr-1 w-[90px] truncate text-left text-sm font-medium text-text-secondary' 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' className='flex h-9 cursor-pointer items-center rounded-lg px-3 hover:bg-state-base-hover'
onClick={() => onSelect(item.credentialId)} onClick={() => onSelect(item.credentialId)}
> >
<NotionIcon <CredentialIcon
className='mr-2 shrink-0' className='mr-2 shrink-0'
src={item.workspaceIcon} avatarUrl={item.workspaceIcon}
name={displayName} name={displayName}
size={20}
/> />
<div <div
className='system-sm-medium mr-2 grow truncate text-text-secondary' 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 NotionIcon from '../../notion-icon'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import type { DataSourceNotionPage, DataSourceNotionPageMap } from '@/models/common' import type { DataSourceNotionPage, DataSourceNotionPageMap } from '@/models/common'
import Radio from '@/app/components/base/radio/ui'
type PageSelectorProps = { type PageSelectorProps = {
value: Set<string> value: Set<string>
@@ -18,6 +19,7 @@ type PageSelectorProps = {
canPreview?: boolean canPreview?: boolean
previewPageId?: string previewPageId?: string
onPreview?: (selectedPageId: string) => void onPreview?: (selectedPageId: string) => void
isMultipleChoice?: boolean
} }
type NotionPageTreeItem = { type NotionPageTreeItem = {
children: Set<string> children: Set<string>
@@ -80,6 +82,7 @@ const ItemComponent = ({ index, style, data }: ListChildComponentProps<{
searchValue: string searchValue: string
previewPageId: string previewPageId: string
pagesMap: DataSourceNotionPageMap pagesMap: DataSourceNotionPageMap
isMultipleChoice?: boolean
}>) => { }>) => {
const { t } = useTranslation() const { t } = useTranslation()
const { const {
@@ -94,6 +97,7 @@ const ItemComponent = ({ index, style, data }: ListChildComponentProps<{
searchValue, searchValue,
previewPageId, previewPageId,
pagesMap, pagesMap,
isMultipleChoice,
} = data } = data
const current = dataList[index] const current = dataList[index]
const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[current.page_id] const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[current.page_id]
@@ -134,16 +138,24 @@ const ItemComponent = ({ index, style, data }: ListChildComponentProps<{
previewPageId === current.page_id && 'bg-state-base-hover')} previewPageId === current.page_id && 'bg-state-base-hover')}
style={{ ...style, top: style.top as number + 8, left: 8, right: 8, width: 'calc(100% - 16px)' }} style={{ ...style, top: style.top as number + 8, left: 8, right: 8, width: 'calc(100% - 16px)' }}
> >
<Checkbox {isMultipleChoice ? (
className='mr-2 shrink-0' <Checkbox
checked={checkedIds.has(current.page_id)} className='mr-2 shrink-0'
disabled={disabled} checked={checkedIds.has(current.page_id)}
onCheck={() => { disabled={disabled}
if (disabled) onCheck={() => {
return handleCheck(index)
handleCheck(index) }}
}} />) : (
/> <Radio
className='mr-2 shrink-0'
isChecked={checkedIds.has(current.page_id)}
disabled={disabled}
onCheck={() => {
handleCheck(index)
}}
/>
)}
{!searchValue && renderArrow()} {!searchValue && renderArrow()}
<NotionIcon <NotionIcon
className='mr-1 shrink-0' className='mr-1 shrink-0'
@@ -192,6 +204,7 @@ const PageSelector = ({
canPreview = true, canPreview = true,
previewPageId, previewPageId,
onPreview, onPreview,
isMultipleChoice = true,
}: PageSelectorProps) => { }: PageSelectorProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const [dataList, setDataList] = useState<NotionPageItem[]>([]) const [dataList, setDataList] = useState<NotionPageItem[]>([])
@@ -265,7 +278,7 @@ const PageSelector = ({
const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[pageId] const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[pageId]
if (copyValue.has(pageId)) { if (copyValue.has(pageId)) {
if (!searchValue) { if (!searchValue && isMultipleChoice) {
for (const item of currentWithChildrenAndDescendants.descendants) for (const item of currentWithChildrenAndDescendants.descendants)
copyValue.delete(item) copyValue.delete(item)
} }
@@ -273,12 +286,18 @@ const PageSelector = ({
copyValue.delete(pageId) copyValue.delete(pageId)
} }
else { else {
if (!searchValue) { if (!searchValue && isMultipleChoice) {
for (const item of currentWithChildrenAndDescendants.descendants) for (const item of currentWithChildrenAndDescendants.descendants)
copyValue.add(item) copyValue.add(item)
} }
// Single choice mode, clear previous selection
copyValue.add(pageId) if (!isMultipleChoice && copyValue.size > 0) {
copyValue.clear()
copyValue.add(pageId)
}
else {
copyValue.add(pageId)
}
} }
onSelect(new Set(copyValue)) onSelect(new Set(copyValue))
@@ -322,6 +341,7 @@ const PageSelector = ({
searchValue, searchValue,
previewPageId: currentPreviewPageId, previewPageId: currentPreviewPageId,
pagesMap, pagesMap,
isMultipleChoice,
}} }}
> >
{Item} {Item}

View File

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

View File

@@ -25,7 +25,7 @@ type IFileUploaderProps = {
onFileUpdate: (fileItem: FileItem, progress: number, list: FileItem[]) => void onFileUpdate: (fileItem: FileItem, progress: number, list: FileItem[]) => void
onFileListUpdate?: (files: FileItem[]) => void onFileListUpdate?: (files: FileItem[]) => void
onPreview: (file: File) => void onPreview: (file: File) => void
notSupportBatchUpload?: boolean supportBatchUpload?: boolean
} }
const FileUploader = ({ const FileUploader = ({
@@ -35,7 +35,7 @@ const FileUploader = ({
onFileUpdate, onFileUpdate,
onFileListUpdate, onFileListUpdate,
onPreview, onPreview,
notSupportBatchUpload, supportBatchUpload = false,
}: IFileUploaderProps) => { }: IFileUploaderProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const { notify } = useContext(ToastContext) const { notify } = useContext(ToastContext)
@@ -44,7 +44,7 @@ const FileUploader = ({
const dropRef = useRef<HTMLDivElement>(null) const dropRef = useRef<HTMLDivElement>(null)
const dragRef = useRef<HTMLDivElement>(null) const dragRef = useRef<HTMLDivElement>(null)
const fileUploader = useRef<HTMLInputElement>(null) const fileUploader = useRef<HTMLInputElement>(null)
const hideUpload = notSupportBatchUpload && fileList.length > 0 const hideUpload = !supportBatchUpload && fileList.length > 0
const { data: fileUploadConfigResponse } = useFileUploadConfig() const { data: fileUploadConfigResponse } = useFileUploadConfig()
const { data: supportFileTypesResponse } = useFileSupportTypes() const { data: supportFileTypesResponse } = useFileSupportTypes()
@@ -68,9 +68,9 @@ const FileUploader = ({
const ACCEPTS = supportTypes.map((ext: string) => `.${ext}`) const ACCEPTS = supportTypes.map((ext: string) => `.${ext}`)
const fileUploadConfig = useMemo(() => ({ const fileUploadConfig = useMemo(() => ({
file_size_limit: fileUploadConfigResponse?.file_size_limit ?? 15, file_size_limit: fileUploadConfigResponse?.file_size_limit ?? 15,
batch_count_limit: fileUploadConfigResponse?.batch_count_limit ?? 5, batch_count_limit: supportBatchUpload ? (fileUploadConfigResponse?.batch_count_limit ?? 5) : 1,
file_upload_limit: fileUploadConfigResponse?.file_upload_limit ?? 5, file_upload_limit: supportBatchUpload ? (fileUploadConfigResponse?.file_upload_limit ?? 5) : 1,
}), [fileUploadConfigResponse]) }), [fileUploadConfigResponse, supportBatchUpload])
const fileListRef = useRef<FileItem[]>([]) const fileListRef = useRef<FileItem[]>([])
@@ -254,12 +254,12 @@ const FileUploader = ({
}), }),
) )
let files = nested.flat() 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) files = files.slice(0, fileUploadConfig.batch_count_limit)
const valid = files.filter(isValid) const valid = files.filter(isValid)
initialUpload(valid) initialUpload(valid)
}, },
[initialUpload, isValid, notSupportBatchUpload, traverseFileEntry, fileUploadConfig], [initialUpload, isValid, supportBatchUpload, traverseFileEntry, fileUploadConfig],
) )
const selectHandle = () => { const selectHandle = () => {
if (fileUploader.current) if (fileUploader.current)
@@ -303,7 +303,7 @@ const FileUploader = ({
id="fileUploader" id="fileUploader"
className="hidden" className="hidden"
type="file" type="file"
multiple={!notSupportBatchUpload} multiple={supportBatchUpload}
accept={ACCEPTS.join(',')} accept={ACCEPTS.join(',')}
onChange={fileChangeHandle} onChange={fileChangeHandle}
/> />
@@ -317,7 +317,7 @@ const FileUploader = ({
<RiUploadCloud2Line className='mr-2 size-5' /> <RiUploadCloud2Line className='mr-2 size-5' />
<span> <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 && ( {supportTypes.length > 0 && (
<label className="ml-1 cursor-pointer text-text-accent" onClick={selectHandle}>{t('datasetCreation.stepOne.uploader.browse')}</label> <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', { <div>{t('datasetCreation.stepOne.uploader.tip', {
size: fileUploadConfig.file_size_limit, size: fileUploadConfig.file_size_limit,
supportTypes: supportTypesShowNames, supportTypes: supportTypesShowNames,
batchCount: notSupportBatchUpload ? 1 : fileUploadConfig.batch_count_limit, batchCount: fileUploadConfig.batch_count_limit,
totalCount: fileUploadConfig.file_upload_limit, totalCount: fileUploadConfig.file_upload_limit,
})}</div> })}</div>
{dragging && <div ref={dragRef} className='absolute left-0 top-0 h-full w-full' />} {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 hasNotin = notionPages.length > 0
const isVectorSpaceFull = plan.usage.vectorSpace >= plan.total.vectorSpace const isVectorSpaceFull = plan.usage.vectorSpace >= plan.total.vectorSpace
const isShowVectorSpaceFull = (allFileLoaded || hasNotin) && isVectorSpaceFull && enableBilling const isShowVectorSpaceFull = (allFileLoaded || hasNotin) && isVectorSpaceFull && enableBilling
const notSupportBatchUpload = enableBilling && plan.type === 'sandbox' const supportBatchUpload = !enableBilling || plan.type !== 'sandbox'
const nextDisabled = useMemo(() => { const nextDisabled = useMemo(() => {
if (!files.length) if (!files.length)
return true return true
@@ -229,7 +229,7 @@ const StepOne = ({
onFileListUpdate={updateFileList} onFileListUpdate={updateFileList}
onFileUpdate={updateFile} onFileUpdate={updateFile}
onPreview={updateCurrentFile} onPreview={updateCurrentFile}
notSupportBatchUpload={notSupportBatchUpload} supportBatchUpload={supportBatchUpload}
/> />
{isShowVectorSpaceFull && ( {isShowVectorSpaceFull && (
<div className='mb-4 max-w-[640px]'> <div className='mb-4 max-w-[640px]'>
@@ -259,6 +259,7 @@ const StepOne = ({
credentialList={notionCredentialList} credentialList={notionCredentialList}
onSelectCredential={updateNotionCredentialId} onSelectCredential={updateNotionCredentialId}
datasetId={datasetId} datasetId={datasetId}
supportBatchUpload={supportBatchUpload}
/> />
</div> </div>
{isShowVectorSpaceFull && ( {isShowVectorSpaceFull && (

View File

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

View File

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

View File

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

View File

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

View File

@@ -26,6 +26,7 @@ type Props = {
onJobIdChange: (jobId: string) => void onJobIdChange: (jobId: string) => void
crawlOptions: CrawlOptions crawlOptions: CrawlOptions
onCrawlOptionsChange: (payload: CrawlOptions) => void onCrawlOptionsChange: (payload: CrawlOptions) => void
supportBatchUpload: boolean
} }
enum Step { enum Step {
@@ -41,6 +42,7 @@ const JinaReader: FC<Props> = ({
onJobIdChange, onJobIdChange,
crawlOptions, crawlOptions,
onCrawlOptionsChange, onCrawlOptionsChange,
supportBatchUpload,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const [step, setStep] = useState<Step>(Step.init) const [step, setStep] = useState<Step>(Step.init)
@@ -157,7 +159,7 @@ const JinaReader: FC<Props> = ({
total: 1, total: 1,
data: [{ data: [{
title, title,
content, markdown: content,
description, description,
source_url: url, source_url: url,
}], }],
@@ -176,7 +178,7 @@ const JinaReader: FC<Props> = ({
} }
else { else {
setCrawlResult(data) 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('') setCrawlErrorMessage('')
} }
} }
@@ -188,7 +190,7 @@ const JinaReader: FC<Props> = ({
finally { finally {
setStep(Step.finished) setStep(Step.finished)
} }
}, [checkValid, crawlOptions, onCheckedCrawlResultChange, onJobIdChange, t, waitForCrawlFinished]) }, [checkValid, crawlOptions, onCheckedCrawlResultChange, onJobIdChange, supportBatchUpload, t, waitForCrawlFinished])
return ( return (
<div> <div>
@@ -227,6 +229,7 @@ const JinaReader: FC<Props> = ({
onSelectedChange={onCheckedCrawlResultChange} onSelectedChange={onCheckedCrawlResultChange}
onPreview={onPreview} onPreview={onPreview}
usedTime={Number.parseFloat(crawlResult?.time_consuming as string) || 0} usedTime={Number.parseFloat(crawlResult?.time_consuming as string) || 0}
isMultipleChoice={supportBatchUpload}
/> />
} }
</div> </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 className='system-xs-medium truncate text-text-tertiary' title={payload.source_url}>{payload.source_url}</div>
</div> </div>
<div className={cn(s.previewContent, 'body-md-regular')}> <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>
</div> </div>
) )

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,8 +11,8 @@ type FileListProps = {
fileList: OnlineDriveFile[] fileList: OnlineDriveFile[]
selectedFileIds: string[] selectedFileIds: string[]
keywords: string keywords: string
isInPipeline: boolean
isLoading: boolean isLoading: boolean
supportBatchUpload: boolean
handleResetKeywords: () => void handleResetKeywords: () => void
handleSelectFile: (file: OnlineDriveFile) => void handleSelectFile: (file: OnlineDriveFile) => void
handleOpenFolder: (file: OnlineDriveFile) => void handleOpenFolder: (file: OnlineDriveFile) => void
@@ -25,8 +25,8 @@ const List = ({
handleResetKeywords, handleResetKeywords,
handleSelectFile, handleSelectFile,
handleOpenFolder, handleOpenFolder,
isInPipeline,
isLoading, isLoading,
supportBatchUpload,
}: FileListProps) => { }: FileListProps) => {
const anchorRef = useRef<HTMLDivElement>(null) const anchorRef = useRef<HTMLDivElement>(null)
const observerRef = useRef<IntersectionObserver>(null) const observerRef = useRef<IntersectionObserver>(null)
@@ -80,7 +80,7 @@ const List = ({
isSelected={isSelected} isSelected={isSelected}
onSelect={handleSelectFile} onSelect={handleSelectFile}
onOpen={handleOpenFolder} 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 = { type OnlineDriveProps = {
nodeId: string nodeId: string
nodeData: DataSourceNodeType nodeData: DataSourceNodeType
isInPipeline?: boolean
onCredentialChange: (credentialId: string) => void onCredentialChange: (credentialId: string) => void
isInPipeline?: boolean
supportBatchUpload?: boolean
} }
const OnlineDrive = ({ const OnlineDrive = ({
nodeId, nodeId,
nodeData, nodeData,
isInPipeline = false, isInPipeline = false,
supportBatchUpload = false,
onCredentialChange, onCredentialChange,
}: OnlineDriveProps) => { }: OnlineDriveProps) => {
const docLink = useDocLink() const docLink = useDocLink()
@@ -111,7 +113,7 @@ const OnlineDrive = ({
}, },
}, },
) )
}, [datasourceNodeRunURL, dataSourceStore]) }, [dataSourceStore, datasourceNodeRunURL, breadcrumbs])
useEffect(() => { useEffect(() => {
if (!currentCredentialId) return if (!currentCredentialId) return
@@ -152,12 +154,12 @@ const OnlineDrive = ({
draft.splice(index, 1) draft.splice(index, 1)
} }
else { else {
if (isInPipeline && draft.length >= 1) return if (!supportBatchUpload && draft.length >= 1) return
draft.push(file.id) draft.push(file.id)
} }
}) })
setSelectedFileIds(newSelectedFileList) setSelectedFileIds(newSelectedFileList)
}, [dataSourceStore, isInPipeline]) }, [dataSourceStore, supportBatchUpload])
const handleOpenFolder = useCallback((file: OnlineDriveFile) => { const handleOpenFolder = useCallback((file: OnlineDriveFile) => {
const { breadcrumbs, prefix, setBreadcrumbs, setPrefix, setBucket, setOnlineDriveFileList, setSelectedFileIds } = dataSourceStore.getState() const { breadcrumbs, prefix, setBreadcrumbs, setPrefix, setBucket, setOnlineDriveFileList, setSelectedFileIds } = dataSourceStore.getState()
@@ -177,7 +179,7 @@ const OnlineDrive = ({
setBreadcrumbs(newBreadcrumbs) setBreadcrumbs(newBreadcrumbs)
setPrefix(newPrefix) setPrefix(newPrefix)
} }
}, [dataSourceStore, getOnlineDriveFiles]) }, [dataSourceStore])
const handleSetting = useCallback(() => { const handleSetting = useCallback(() => {
setShowAccountSettingModal({ setShowAccountSettingModal({
@@ -209,6 +211,7 @@ const OnlineDrive = ({
handleOpenFolder={handleOpenFolder} handleOpenFolder={handleOpenFolder}
isInPipeline={isInPipeline} isInPipeline={isInPipeline}
isLoading={isLoading} isLoading={isLoading}
supportBatchUpload={supportBatchUpload}
/> />
</div> </div>
) )

View File

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

View File

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

View File

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

View File

@@ -27,7 +27,7 @@ const WebsitePreview = ({
<span className='uppercase' title={currentWebsite.source_url}>{currentWebsite.source_url}</span> <span className='uppercase' title={currentWebsite.source_url}>{currentWebsite.source_url}</span>
<span>·</span> <span>·</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>
</div> </div>
<button <button
@@ -39,7 +39,7 @@ const WebsitePreview = ({
</button> </button>
</div> </div>
<div className='body-md-regular grow overflow-hidden px-6 py-5 text-text-secondary'> <div className='body-md-regular grow overflow-hidden px-6 py-5 text-text-secondary'>
{currentWebsite.content} {currentWebsite.markdown}
</div> </div>
</div> </div>
) )

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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