mirror of https://github.com/langgenius/dify.git
feat: implement dataset creation step one with preview functionality (#30507)
Co-authored-by: CodingOnStar <hanxujiang@dify.ai>
This commit is contained in:
parent
2cc89d30db
commit
64bfcbc4a9
|
|
@ -0,0 +1,97 @@
|
|||
'use client'
|
||||
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { ENABLE_WEBSITE_FIRECRAWL, ENABLE_WEBSITE_JINAREADER, ENABLE_WEBSITE_WATERCRAWL } from '@/config'
|
||||
import { DataSourceType } from '@/models/datasets'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import s from '../index.module.css'
|
||||
|
||||
type DataSourceTypeSelectorProps = {
|
||||
currentType: DataSourceType
|
||||
disabled: boolean
|
||||
onChange: (type: DataSourceType) => void
|
||||
onClearPreviews: (type: DataSourceType) => void
|
||||
}
|
||||
|
||||
type DataSourceLabelKey
|
||||
= | 'stepOne.dataSourceType.file'
|
||||
| 'stepOne.dataSourceType.notion'
|
||||
| 'stepOne.dataSourceType.web'
|
||||
|
||||
type DataSourceOption = {
|
||||
type: DataSourceType
|
||||
iconClass?: string
|
||||
labelKey: DataSourceLabelKey
|
||||
}
|
||||
|
||||
const DATA_SOURCE_OPTIONS: DataSourceOption[] = [
|
||||
{
|
||||
type: DataSourceType.FILE,
|
||||
labelKey: 'stepOne.dataSourceType.file',
|
||||
},
|
||||
{
|
||||
type: DataSourceType.NOTION,
|
||||
iconClass: s.notion,
|
||||
labelKey: 'stepOne.dataSourceType.notion',
|
||||
},
|
||||
{
|
||||
type: DataSourceType.WEB,
|
||||
iconClass: s.web,
|
||||
labelKey: 'stepOne.dataSourceType.web',
|
||||
},
|
||||
]
|
||||
|
||||
/**
|
||||
* Data source type selector component for choosing between file, notion, and web sources.
|
||||
*/
|
||||
function DataSourceTypeSelector({
|
||||
currentType,
|
||||
disabled,
|
||||
onChange,
|
||||
onClearPreviews,
|
||||
}: DataSourceTypeSelectorProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const isWebEnabled = ENABLE_WEBSITE_FIRECRAWL || ENABLE_WEBSITE_JINAREADER || ENABLE_WEBSITE_WATERCRAWL
|
||||
|
||||
const handleTypeChange = useCallback((type: DataSourceType) => {
|
||||
if (disabled)
|
||||
return
|
||||
onChange(type)
|
||||
onClearPreviews(type)
|
||||
}, [disabled, onChange, onClearPreviews])
|
||||
|
||||
const visibleOptions = useMemo(() => DATA_SOURCE_OPTIONS.filter((option) => {
|
||||
if (option.type === DataSourceType.WEB)
|
||||
return isWebEnabled
|
||||
return true
|
||||
}), [isWebEnabled])
|
||||
|
||||
return (
|
||||
<div className="mb-8 grid grid-cols-3 gap-4">
|
||||
{visibleOptions.map(option => (
|
||||
<div
|
||||
key={option.type}
|
||||
className={cn(
|
||||
s.dataSourceItem,
|
||||
'system-sm-medium',
|
||||
currentType === option.type && s.active,
|
||||
disabled && currentType !== option.type && s.disabled,
|
||||
)}
|
||||
onClick={() => handleTypeChange(option.type)}
|
||||
>
|
||||
<span className={cn(s.datasetIcon, option.iconClass)} />
|
||||
<span
|
||||
title={t(option.labelKey, { ns: 'datasetCreation' }) || undefined}
|
||||
className="truncate"
|
||||
>
|
||||
{t(option.labelKey, { ns: 'datasetCreation' })}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DataSourceTypeSelector
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export { default as DataSourceTypeSelector } from './data-source-type-selector'
|
||||
export { default as NextStepButton } from './next-step-button'
|
||||
export { default as PreviewPanel } from './preview-panel'
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
'use client'
|
||||
|
||||
import { RiArrowRightLine } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
|
||||
type NextStepButtonProps = {
|
||||
disabled: boolean
|
||||
onClick: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Reusable next step button component for dataset creation flow.
|
||||
*/
|
||||
function NextStepButton({ disabled, onClick }: NextStepButtonProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className="flex max-w-[640px] justify-end gap-2">
|
||||
<Button disabled={disabled} variant="primary" onClick={onClick}>
|
||||
<span className="flex gap-0.5 px-[10px]">
|
||||
<span className="px-0.5">{t('stepOne.button', { ns: 'datasetCreation' })}</span>
|
||||
<RiArrowRightLine className="size-4" />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default NextStepButton
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
'use client'
|
||||
|
||||
import type { NotionPage } from '@/models/common'
|
||||
import type { CrawlResultItem } from '@/models/datasets'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import PlanUpgradeModal from '@/app/components/billing/plan-upgrade-modal'
|
||||
import FilePreview from '../../file-preview'
|
||||
import NotionPagePreview from '../../notion-page-preview'
|
||||
import WebsitePreview from '../../website/preview'
|
||||
|
||||
type PreviewPanelProps = {
|
||||
currentFile: File | undefined
|
||||
currentNotionPage: NotionPage | undefined
|
||||
currentWebsite: CrawlResultItem | undefined
|
||||
notionCredentialId: string
|
||||
isShowPlanUpgradeModal: boolean
|
||||
hideFilePreview: () => void
|
||||
hideNotionPagePreview: () => void
|
||||
hideWebsitePreview: () => void
|
||||
hidePlanUpgradeModal: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Right panel component for displaying file, notion page, or website previews.
|
||||
*/
|
||||
function PreviewPanel({
|
||||
currentFile,
|
||||
currentNotionPage,
|
||||
currentWebsite,
|
||||
notionCredentialId,
|
||||
isShowPlanUpgradeModal,
|
||||
hideFilePreview,
|
||||
hideNotionPagePreview,
|
||||
hideWebsitePreview,
|
||||
hidePlanUpgradeModal,
|
||||
}: PreviewPanelProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className="h-full w-1/2 overflow-y-auto">
|
||||
{currentFile && <FilePreview file={currentFile} hidePreview={hideFilePreview} />}
|
||||
{currentNotionPage && (
|
||||
<NotionPagePreview
|
||||
currentPage={currentNotionPage}
|
||||
hidePreview={hideNotionPagePreview}
|
||||
notionCredentialId={notionCredentialId}
|
||||
/>
|
||||
)}
|
||||
{currentWebsite && <WebsitePreview payload={currentWebsite} hidePreview={hideWebsitePreview} />}
|
||||
{isShowPlanUpgradeModal && (
|
||||
<PlanUpgradeModal
|
||||
show
|
||||
onClose={hidePlanUpgradeModal}
|
||||
title={t('upgrade.uploadMultiplePages.title', { ns: 'billing' })!}
|
||||
description={t('upgrade.uploadMultiplePages.description', { ns: 'billing' })!}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PreviewPanel
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
export { default as usePreviewState } from './use-preview-state'
|
||||
export type { PreviewActions, PreviewState, UsePreviewStateReturn } from './use-preview-state'
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
'use client'
|
||||
|
||||
import type { NotionPage } from '@/models/common'
|
||||
import type { CrawlResultItem } from '@/models/datasets'
|
||||
import { useCallback, useState } from 'react'
|
||||
|
||||
export type PreviewState = {
|
||||
currentFile: File | undefined
|
||||
currentNotionPage: NotionPage | undefined
|
||||
currentWebsite: CrawlResultItem | undefined
|
||||
}
|
||||
|
||||
export type PreviewActions = {
|
||||
showFilePreview: (file: File) => void
|
||||
hideFilePreview: () => void
|
||||
showNotionPagePreview: (page: NotionPage) => void
|
||||
hideNotionPagePreview: () => void
|
||||
showWebsitePreview: (website: CrawlResultItem) => void
|
||||
hideWebsitePreview: () => void
|
||||
}
|
||||
|
||||
export type UsePreviewStateReturn = PreviewState & PreviewActions
|
||||
|
||||
/**
|
||||
* Custom hook for managing preview state across different data source types.
|
||||
* Handles file, notion page, and website preview visibility.
|
||||
*/
|
||||
function usePreviewState(): UsePreviewStateReturn {
|
||||
const [currentFile, setCurrentFile] = useState<File | undefined>()
|
||||
const [currentNotionPage, setCurrentNotionPage] = useState<NotionPage | undefined>()
|
||||
const [currentWebsite, setCurrentWebsite] = useState<CrawlResultItem | undefined>()
|
||||
|
||||
const showFilePreview = useCallback((file: File) => {
|
||||
setCurrentFile(file)
|
||||
}, [])
|
||||
|
||||
const hideFilePreview = useCallback(() => {
|
||||
setCurrentFile(undefined)
|
||||
}, [])
|
||||
|
||||
const showNotionPagePreview = useCallback((page: NotionPage) => {
|
||||
setCurrentNotionPage(page)
|
||||
}, [])
|
||||
|
||||
const hideNotionPagePreview = useCallback(() => {
|
||||
setCurrentNotionPage(undefined)
|
||||
}, [])
|
||||
|
||||
const showWebsitePreview = useCallback((website: CrawlResultItem) => {
|
||||
setCurrentWebsite(website)
|
||||
}, [])
|
||||
|
||||
const hideWebsitePreview = useCallback(() => {
|
||||
setCurrentWebsite(undefined)
|
||||
}, [])
|
||||
|
||||
return {
|
||||
currentFile,
|
||||
currentNotionPage,
|
||||
currentWebsite,
|
||||
showFilePreview,
|
||||
hideFilePreview,
|
||||
showNotionPagePreview,
|
||||
hideNotionPagePreview,
|
||||
showWebsitePreview,
|
||||
hideWebsitePreview,
|
||||
}
|
||||
}
|
||||
|
||||
export default usePreviewState
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,29 +1,25 @@
|
|||
'use client'
|
||||
|
||||
import type { DataSourceAuth } from '@/app/components/header/account-setting/data-source-page-new/types'
|
||||
import type { DataSourceProvider, NotionPage } from '@/models/common'
|
||||
import type { CrawlOptions, CrawlResultItem, FileItem } from '@/models/datasets'
|
||||
import { RiArrowRightLine, RiFolder6Line } from '@remixicon/react'
|
||||
import { RiFolder6Line } from '@remixicon/react'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import * as React from 'react'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import NotionConnector from '@/app/components/base/notion-connector'
|
||||
import { NotionPageSelector } from '@/app/components/base/notion-page-selector'
|
||||
import PlanUpgradeModal from '@/app/components/billing/plan-upgrade-modal'
|
||||
import { Plan } from '@/app/components/billing/type'
|
||||
import VectorSpaceFull from '@/app/components/billing/vector-space-full'
|
||||
import { ENABLE_WEBSITE_FIRECRAWL, ENABLE_WEBSITE_JINAREADER, ENABLE_WEBSITE_WATERCRAWL } from '@/config'
|
||||
import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { DataSourceType } from '@/models/datasets'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import EmptyDatasetCreationModal from '../empty-dataset-creation-modal'
|
||||
import FilePreview from '../file-preview'
|
||||
import FileUploader from '../file-uploader'
|
||||
import NotionPagePreview from '../notion-page-preview'
|
||||
import Website from '../website'
|
||||
import WebsitePreview from '../website/preview'
|
||||
import { DataSourceTypeSelector, NextStepButton, PreviewPanel } from './components'
|
||||
import { usePreviewState } from './hooks'
|
||||
import s from './index.module.css'
|
||||
import UpgradeCard from './upgrade-card'
|
||||
|
||||
|
|
@ -50,6 +46,24 @@ type IStepOneProps = {
|
|||
authedDataSourceList: DataSourceAuth[]
|
||||
}
|
||||
|
||||
// Helper function to check if notion is authenticated
|
||||
function checkNotionAuth(authedDataSourceList: DataSourceAuth[]): boolean {
|
||||
const notionSource = authedDataSourceList.find(item => item.provider === 'notion_datasource')
|
||||
return Boolean(notionSource && notionSource.credentials_list.length > 0)
|
||||
}
|
||||
|
||||
// Helper function to get notion credential list
|
||||
function getNotionCredentialList(authedDataSourceList: DataSourceAuth[]) {
|
||||
return authedDataSourceList.find(item => item.provider === 'notion_datasource')?.credentials_list || []
|
||||
}
|
||||
|
||||
// Lookup table for checking multiple items by data source type
|
||||
const MULTIPLE_ITEMS_CHECK: Record<DataSourceType, (props: { files: FileItem[], notionPages: NotionPage[], websitePages: CrawlResultItem[] }) => boolean> = {
|
||||
[DataSourceType.FILE]: ({ files }) => files.length > 1,
|
||||
[DataSourceType.NOTION]: ({ notionPages }) => notionPages.length > 1,
|
||||
[DataSourceType.WEB]: ({ websitePages }) => websitePages.length > 1,
|
||||
}
|
||||
|
||||
const StepOne = ({
|
||||
datasetId,
|
||||
dataSourceType: inCreatePageDataSourceType,
|
||||
|
|
@ -72,76 +86,47 @@ const StepOne = ({
|
|||
onCrawlOptionsChange,
|
||||
authedDataSourceList,
|
||||
}: IStepOneProps) => {
|
||||
const dataset = useDatasetDetailContextWithSelector(state => state.dataset)
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
const [currentFile, setCurrentFile] = useState<File | undefined>()
|
||||
const [currentNotionPage, setCurrentNotionPage] = useState<NotionPage | undefined>()
|
||||
const [currentWebsite, setCurrentWebsite] = useState<CrawlResultItem | undefined>()
|
||||
const { t } = useTranslation()
|
||||
const dataset = useDatasetDetailContextWithSelector(state => state.dataset)
|
||||
const { plan, enableBilling } = useProviderContext()
|
||||
|
||||
const modalShowHandle = () => setShowModal(true)
|
||||
const modalCloseHandle = () => setShowModal(false)
|
||||
// Preview state management
|
||||
const {
|
||||
currentFile,
|
||||
currentNotionPage,
|
||||
currentWebsite,
|
||||
showFilePreview,
|
||||
hideFilePreview,
|
||||
showNotionPagePreview,
|
||||
hideNotionPagePreview,
|
||||
showWebsitePreview,
|
||||
hideWebsitePreview,
|
||||
} = usePreviewState()
|
||||
|
||||
const updateCurrentFile = useCallback((file: File) => {
|
||||
setCurrentFile(file)
|
||||
}, [])
|
||||
// Empty dataset modal state
|
||||
const [showModal, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false)
|
||||
|
||||
const hideFilePreview = useCallback(() => {
|
||||
setCurrentFile(undefined)
|
||||
}, [])
|
||||
|
||||
const updateCurrentPage = useCallback((page: NotionPage) => {
|
||||
setCurrentNotionPage(page)
|
||||
}, [])
|
||||
|
||||
const hideNotionPagePreview = useCallback(() => {
|
||||
setCurrentNotionPage(undefined)
|
||||
}, [])
|
||||
|
||||
const updateWebsite = useCallback((website: CrawlResultItem) => {
|
||||
setCurrentWebsite(website)
|
||||
}, [])
|
||||
|
||||
const hideWebsitePreview = useCallback(() => {
|
||||
setCurrentWebsite(undefined)
|
||||
}, [])
|
||||
// Plan upgrade modal state
|
||||
const [isShowPlanUpgradeModal, { setTrue: showPlanUpgradeModal, setFalse: hidePlanUpgradeModal }] = useBoolean(false)
|
||||
|
||||
// Computed values
|
||||
const shouldShowDataSourceTypeList = !datasetId || (datasetId && !dataset?.data_source_type)
|
||||
const isInCreatePage = shouldShowDataSourceTypeList
|
||||
const dataSourceType = isInCreatePage ? inCreatePageDataSourceType : dataset?.data_source_type
|
||||
const { plan, enableBilling } = useProviderContext()
|
||||
const allFileLoaded = (files.length > 0 && files.every(file => file.file.id))
|
||||
const hasNotin = notionPages.length > 0
|
||||
// Default to FILE type when no type is provided from either source
|
||||
const dataSourceType = isInCreatePage
|
||||
? (inCreatePageDataSourceType ?? DataSourceType.FILE)
|
||||
: (dataset?.data_source_type ?? DataSourceType.FILE)
|
||||
|
||||
const allFileLoaded = files.length > 0 && files.every(file => file.file.id)
|
||||
const hasNotion = notionPages.length > 0
|
||||
const isVectorSpaceFull = plan.usage.vectorSpace >= plan.total.vectorSpace
|
||||
const isShowVectorSpaceFull = (allFileLoaded || hasNotin) && isVectorSpaceFull && enableBilling
|
||||
const isShowVectorSpaceFull = (allFileLoaded || hasNotion) && isVectorSpaceFull && enableBilling
|
||||
const supportBatchUpload = !enableBilling || plan.type !== Plan.sandbox
|
||||
const notSupportBatchUpload = !supportBatchUpload
|
||||
|
||||
const [isShowPlanUpgradeModal, {
|
||||
setTrue: showPlanUpgradeModal,
|
||||
setFalse: hidePlanUpgradeModal,
|
||||
}] = useBoolean(false)
|
||||
const onStepChange = useCallback(() => {
|
||||
if (notSupportBatchUpload) {
|
||||
let isMultiple = false
|
||||
if (dataSourceType === DataSourceType.FILE && files.length > 1)
|
||||
isMultiple = true
|
||||
const isNotionAuthed = useMemo(() => checkNotionAuth(authedDataSourceList), [authedDataSourceList])
|
||||
const notionCredentialList = useMemo(() => getNotionCredentialList(authedDataSourceList), [authedDataSourceList])
|
||||
|
||||
if (dataSourceType === DataSourceType.NOTION && notionPages.length > 1)
|
||||
isMultiple = true
|
||||
|
||||
if (dataSourceType === DataSourceType.WEB && websitePages.length > 1)
|
||||
isMultiple = true
|
||||
|
||||
if (isMultiple) {
|
||||
showPlanUpgradeModal()
|
||||
return
|
||||
}
|
||||
}
|
||||
doOnStepChange()
|
||||
}, [dataSourceType, doOnStepChange, files.length, notSupportBatchUpload, notionPages.length, showPlanUpgradeModal, websitePages.length])
|
||||
|
||||
const nextDisabled = useMemo(() => {
|
||||
const fileNextDisabled = useMemo(() => {
|
||||
if (!files.length)
|
||||
return true
|
||||
if (files.some(file => !file.file.id))
|
||||
|
|
@ -149,109 +134,50 @@ const StepOne = ({
|
|||
return isShowVectorSpaceFull
|
||||
}, [files, isShowVectorSpaceFull])
|
||||
|
||||
const isNotionAuthed = useMemo(() => {
|
||||
if (!authedDataSourceList)
|
||||
return false
|
||||
const notionSource = authedDataSourceList.find(item => item.provider === 'notion_datasource')
|
||||
if (!notionSource)
|
||||
return false
|
||||
return notionSource.credentials_list.length > 0
|
||||
}, [authedDataSourceList])
|
||||
// Clear previews when switching data source type
|
||||
const handleClearPreviews = useCallback((newType: DataSourceType) => {
|
||||
if (newType !== DataSourceType.FILE)
|
||||
hideFilePreview()
|
||||
if (newType !== DataSourceType.NOTION)
|
||||
hideNotionPagePreview()
|
||||
if (newType !== DataSourceType.WEB)
|
||||
hideWebsitePreview()
|
||||
}, [hideFilePreview, hideNotionPagePreview, hideWebsitePreview])
|
||||
|
||||
const notionCredentialList = useMemo(() => {
|
||||
return authedDataSourceList.find(item => item.provider === 'notion_datasource')?.credentials_list || []
|
||||
}, [authedDataSourceList])
|
||||
// Handle step change with batch upload check
|
||||
const onStepChange = useCallback(() => {
|
||||
if (!supportBatchUpload && dataSourceType) {
|
||||
const checkFn = MULTIPLE_ITEMS_CHECK[dataSourceType]
|
||||
if (checkFn?.({ files, notionPages, websitePages })) {
|
||||
showPlanUpgradeModal()
|
||||
return
|
||||
}
|
||||
}
|
||||
doOnStepChange()
|
||||
}, [dataSourceType, doOnStepChange, files, supportBatchUpload, notionPages, showPlanUpgradeModal, websitePages])
|
||||
|
||||
return (
|
||||
<div className="h-full w-full overflow-x-auto">
|
||||
<div className="flex h-full w-full min-w-[1440px]">
|
||||
{/* Left Panel - Form */}
|
||||
<div className="relative h-full w-1/2 overflow-y-auto">
|
||||
<div className="flex justify-end">
|
||||
<div className={cn(s.form)}>
|
||||
{
|
||||
shouldShowDataSourceTypeList && (
|
||||
{shouldShowDataSourceTypeList && (
|
||||
<>
|
||||
<div className={cn(s.stepHeader, 'system-md-semibold text-text-secondary')}>
|
||||
{t('steps.one', { ns: 'datasetCreation' })}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
shouldShowDataSourceTypeList && (
|
||||
<div className="mb-8 grid grid-cols-3 gap-4">
|
||||
<div
|
||||
className={cn(
|
||||
s.dataSourceItem,
|
||||
'system-sm-medium',
|
||||
dataSourceType === DataSourceType.FILE && s.active,
|
||||
dataSourceTypeDisable && dataSourceType !== DataSourceType.FILE && s.disabled,
|
||||
)}
|
||||
onClick={() => {
|
||||
if (dataSourceTypeDisable)
|
||||
return
|
||||
changeType(DataSourceType.FILE)
|
||||
hideNotionPagePreview()
|
||||
hideWebsitePreview()
|
||||
}}
|
||||
>
|
||||
<span className={cn(s.datasetIcon)} />
|
||||
<span
|
||||
title={t('stepOne.dataSourceType.file', { ns: 'datasetCreation' })!}
|
||||
className="truncate"
|
||||
>
|
||||
{t('stepOne.dataSourceType.file', { ns: 'datasetCreation' })}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
s.dataSourceItem,
|
||||
'system-sm-medium',
|
||||
dataSourceType === DataSourceType.NOTION && s.active,
|
||||
dataSourceTypeDisable && dataSourceType !== DataSourceType.NOTION && s.disabled,
|
||||
)}
|
||||
onClick={() => {
|
||||
if (dataSourceTypeDisable)
|
||||
return
|
||||
changeType(DataSourceType.NOTION)
|
||||
hideFilePreview()
|
||||
hideWebsitePreview()
|
||||
}}
|
||||
>
|
||||
<span className={cn(s.datasetIcon, s.notion)} />
|
||||
<span
|
||||
title={t('stepOne.dataSourceType.notion', { ns: 'datasetCreation' })!}
|
||||
className="truncate"
|
||||
>
|
||||
{t('stepOne.dataSourceType.notion', { ns: 'datasetCreation' })}
|
||||
</span>
|
||||
</div>
|
||||
{(ENABLE_WEBSITE_FIRECRAWL || ENABLE_WEBSITE_JINAREADER || ENABLE_WEBSITE_WATERCRAWL) && (
|
||||
<div
|
||||
className={cn(
|
||||
s.dataSourceItem,
|
||||
'system-sm-medium',
|
||||
dataSourceType === DataSourceType.WEB && s.active,
|
||||
dataSourceTypeDisable && dataSourceType !== DataSourceType.WEB && s.disabled,
|
||||
)}
|
||||
onClick={() => {
|
||||
if (dataSourceTypeDisable)
|
||||
return
|
||||
changeType(DataSourceType.WEB)
|
||||
hideFilePreview()
|
||||
hideNotionPagePreview()
|
||||
}}
|
||||
>
|
||||
<span className={cn(s.datasetIcon, s.web)} />
|
||||
<span
|
||||
title={t('stepOne.dataSourceType.web', { ns: 'datasetCreation' })!}
|
||||
className="truncate"
|
||||
>
|
||||
{t('stepOne.dataSourceType.web', { ns: 'datasetCreation' })}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<DataSourceTypeSelector
|
||||
currentType={dataSourceType}
|
||||
disabled={dataSourceTypeDisable}
|
||||
onChange={changeType}
|
||||
onClearPreviews={handleClearPreviews}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* File Data Source */}
|
||||
{dataSourceType === DataSourceType.FILE && (
|
||||
<>
|
||||
<FileUploader
|
||||
|
|
@ -260,7 +186,7 @@ const StepOne = ({
|
|||
prepareFileList={updateFileList}
|
||||
onFileListUpdate={updateFileList}
|
||||
onFileUpdate={updateFile}
|
||||
onPreview={updateCurrentFile}
|
||||
onPreview={showFilePreview}
|
||||
supportBatchUpload={supportBatchUpload}
|
||||
/>
|
||||
{isShowVectorSpaceFull && (
|
||||
|
|
@ -268,24 +194,17 @@ const StepOne = ({
|
|||
<VectorSpaceFull />
|
||||
</div>
|
||||
)}
|
||||
<div className="flex max-w-[640px] justify-end gap-2">
|
||||
<Button disabled={nextDisabled} variant="primary" onClick={onStepChange}>
|
||||
<span className="flex gap-0.5 px-[10px]">
|
||||
<span className="px-0.5">{t('stepOne.button', { ns: 'datasetCreation' })}</span>
|
||||
<RiArrowRightLine className="size-4" />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
{
|
||||
enableBilling && plan.type === Plan.sandbox && files.length > 0 && (
|
||||
<div className="mt-5">
|
||||
<div className="mb-4 h-px bg-divider-subtle"></div>
|
||||
<UpgradeCard />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<NextStepButton disabled={fileNextDisabled} onClick={onStepChange} />
|
||||
{enableBilling && plan.type === Plan.sandbox && files.length > 0 && (
|
||||
<div className="mt-5">
|
||||
<div className="mb-4 h-px bg-divider-subtle" />
|
||||
<UpgradeCard />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Notion Data Source */}
|
||||
{dataSourceType === DataSourceType.NOTION && (
|
||||
<>
|
||||
{!isNotionAuthed && <NotionConnector onSetting={onSetting} />}
|
||||
|
|
@ -295,7 +214,7 @@ const StepOne = ({
|
|||
<NotionPageSelector
|
||||
value={notionPages.map(page => page.page_id)}
|
||||
onSelect={updateNotionPages}
|
||||
onPreview={updateCurrentPage}
|
||||
onPreview={showNotionPagePreview}
|
||||
credentialList={notionCredentialList}
|
||||
onSelectCredential={updateNotionCredentialId}
|
||||
datasetId={datasetId}
|
||||
|
|
@ -306,23 +225,21 @@ const StepOne = ({
|
|||
<VectorSpaceFull />
|
||||
</div>
|
||||
)}
|
||||
<div className="flex max-w-[640px] justify-end gap-2">
|
||||
<Button disabled={isShowVectorSpaceFull || !notionPages.length} variant="primary" onClick={onStepChange}>
|
||||
<span className="flex gap-0.5 px-[10px]">
|
||||
<span className="px-0.5">{t('stepOne.button', { ns: 'datasetCreation' })}</span>
|
||||
<RiArrowRightLine className="size-4" />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
<NextStepButton
|
||||
disabled={isShowVectorSpaceFull || !notionPages.length}
|
||||
onClick={onStepChange}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Web Data Source */}
|
||||
{dataSourceType === DataSourceType.WEB && (
|
||||
<>
|
||||
<div className={cn('mb-8 w-[640px]', !shouldShowDataSourceTypeList && 'mt-12')}>
|
||||
<Website
|
||||
onPreview={updateWebsite}
|
||||
onPreview={showWebsitePreview}
|
||||
checkedCrawlResult={websitePages}
|
||||
onCheckedCrawlResultChange={updateWebsitePages}
|
||||
onCrawlProviderChange={onWebsiteCrawlProviderChange}
|
||||
|
|
@ -337,48 +254,43 @@ const StepOne = ({
|
|||
<VectorSpaceFull />
|
||||
</div>
|
||||
)}
|
||||
<div className="flex max-w-[640px] justify-end gap-2">
|
||||
<Button disabled={isShowVectorSpaceFull || !websitePages.length} variant="primary" onClick={onStepChange}>
|
||||
<span className="flex gap-0.5 px-[10px]">
|
||||
<span className="px-0.5">{t('stepOne.button', { ns: 'datasetCreation' })}</span>
|
||||
<RiArrowRightLine className="size-4" />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
<NextStepButton
|
||||
disabled={isShowVectorSpaceFull || !websitePages.length}
|
||||
onClick={onStepChange}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Empty Dataset Creation Link */}
|
||||
{!datasetId && (
|
||||
<>
|
||||
<div className="my-8 h-px max-w-[640px] bg-divider-regular" />
|
||||
<span className="inline-flex cursor-pointer items-center text-[13px] leading-4 text-text-accent" onClick={modalShowHandle}>
|
||||
<span
|
||||
className="inline-flex cursor-pointer items-center text-[13px] leading-4 text-text-accent"
|
||||
onClick={openModal}
|
||||
>
|
||||
<RiFolder6Line className="mr-1 size-4" />
|
||||
{t('stepOne.emptyDatasetCreation', { ns: 'datasetCreation' })}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<EmptyDatasetCreationModal show={showModal} onHide={modalCloseHandle} />
|
||||
<EmptyDatasetCreationModal show={showModal} onHide={closeModal} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-full w-1/2 overflow-y-auto">
|
||||
{currentFile && <FilePreview file={currentFile} hidePreview={hideFilePreview} />}
|
||||
{currentNotionPage && (
|
||||
<NotionPagePreview
|
||||
currentPage={currentNotionPage}
|
||||
hidePreview={hideNotionPagePreview}
|
||||
notionCredentialId={notionCredentialId}
|
||||
/>
|
||||
)}
|
||||
{currentWebsite && <WebsitePreview payload={currentWebsite} hidePreview={hideWebsitePreview} />}
|
||||
{isShowPlanUpgradeModal && (
|
||||
<PlanUpgradeModal
|
||||
show
|
||||
onClose={hidePlanUpgradeModal}
|
||||
title={t('upgrade.uploadMultiplePages.title', { ns: 'billing' })!}
|
||||
description={t('upgrade.uploadMultiplePages.description', { ns: 'billing' })!}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Right Panel - Preview */}
|
||||
<PreviewPanel
|
||||
currentFile={currentFile}
|
||||
currentNotionPage={currentNotionPage}
|
||||
currentWebsite={currentWebsite}
|
||||
notionCredentialId={notionCredentialId}
|
||||
isShowPlanUpgradeModal={isShowPlanUpgradeModal}
|
||||
hideFilePreview={hideFilePreview}
|
||||
hideNotionPagePreview={hideNotionPagePreview}
|
||||
hideWebsitePreview={hideWebsitePreview}
|
||||
hidePlanUpgradeModal={hidePlanUpgradeModal}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue