|
'use client' |
|
import React, { useMemo, useState } from 'react' |
|
import { useTranslation } from 'react-i18next' |
|
import FilePreview from '../file-preview' |
|
import FileUploader from '../file-uploader' |
|
import NotionPagePreview from '../notion-page-preview' |
|
import EmptyDatasetCreationModal from '../empty-dataset-creation-modal' |
|
import Website from '../website' |
|
import WebsitePreview from '../website/preview' |
|
import s from './index.module.css' |
|
import cn from '@/utils/classnames' |
|
import type { CrawlOptions, CrawlResultItem, FileItem } from '@/models/datasets' |
|
import type { DataSourceProvider, NotionPage } from '@/models/common' |
|
import { DataSourceType } from '@/models/datasets' |
|
import Button from '@/app/components/base/button' |
|
import { NotionPageSelector } from '@/app/components/base/notion-page-selector' |
|
import { useDatasetDetailContext } from '@/context/dataset-detail' |
|
import { useProviderContext } from '@/context/provider-context' |
|
import VectorSpaceFull from '@/app/components/billing/vector-space-full' |
|
|
|
type IStepOneProps = { |
|
datasetId?: string |
|
dataSourceType?: DataSourceType |
|
dataSourceTypeDisable: Boolean |
|
hasConnection: boolean |
|
onSetting: () => void |
|
files: FileItem[] |
|
updateFileList: (files: FileItem[]) => void |
|
updateFile: (fileItem: FileItem, progress: number, list: FileItem[]) => void |
|
notionPages?: NotionPage[] |
|
updateNotionPages: (value: NotionPage[]) => void |
|
onStepChange: () => void |
|
changeType: (type: DataSourceType) => void |
|
websitePages?: CrawlResultItem[] |
|
updateWebsitePages: (value: CrawlResultItem[]) => void |
|
onWebsiteCrawlProviderChange: (provider: DataSourceProvider) => void |
|
onWebsiteCrawlJobIdChange: (jobId: string) => void |
|
crawlOptions: CrawlOptions |
|
onCrawlOptionsChange: (payload: CrawlOptions) => void |
|
} |
|
|
|
type NotionConnectorProps = { |
|
onSetting: () => void |
|
} |
|
export const NotionConnector = ({ onSetting }: NotionConnectorProps) => { |
|
const { t } = useTranslation() |
|
|
|
return ( |
|
<div className={s.notionConnectionTip}> |
|
<span className={s.notionIcon} /> |
|
<div className={s.title}>{t('datasetCreation.stepOne.notionSyncTitle')}</div> |
|
<div className={s.tip}>{t('datasetCreation.stepOne.notionSyncTip')}</div> |
|
<Button className='h-8' variant='primary' onClick={onSetting}>{t('datasetCreation.stepOne.connect')}</Button> |
|
</div> |
|
) |
|
} |
|
|
|
const StepOne = ({ |
|
datasetId, |
|
dataSourceType: inCreatePageDataSourceType, |
|
dataSourceTypeDisable, |
|
changeType, |
|
hasConnection, |
|
onSetting, |
|
onStepChange, |
|
files, |
|
updateFileList, |
|
updateFile, |
|
notionPages = [], |
|
updateNotionPages, |
|
websitePages = [], |
|
updateWebsitePages, |
|
onWebsiteCrawlProviderChange, |
|
onWebsiteCrawlJobIdChange, |
|
crawlOptions, |
|
onCrawlOptionsChange, |
|
}: IStepOneProps) => { |
|
const { dataset } = useDatasetDetailContext() |
|
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 modalShowHandle = () => setShowModal(true) |
|
const modalCloseHandle = () => setShowModal(false) |
|
|
|
const updateCurrentFile = (file: File) => { |
|
setCurrentFile(file) |
|
} |
|
const hideFilePreview = () => { |
|
setCurrentFile(undefined) |
|
} |
|
|
|
const updateCurrentPage = (page: NotionPage) => { |
|
setCurrentNotionPage(page) |
|
} |
|
|
|
const hideNotionPagePreview = () => { |
|
setCurrentNotionPage(undefined) |
|
} |
|
|
|
const hideWebsitePreview = () => { |
|
setCurrentWebsite(undefined) |
|
} |
|
|
|
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 |
|
const isVectorSpaceFull = plan.usage.vectorSpace >= plan.total.vectorSpace |
|
const isShowVectorSpaceFull = (allFileLoaded || hasNotin) && isVectorSpaceFull && enableBilling |
|
const notSupportBatchUpload = enableBilling && plan.type === 'sandbox' |
|
const nextDisabled = useMemo(() => { |
|
if (!files.length) |
|
return true |
|
if (files.some(file => !file.file.id)) |
|
return true |
|
if (isShowVectorSpaceFull) |
|
return true |
|
|
|
return false |
|
}, [files]) |
|
return ( |
|
<div className='flex w-full h-full'> |
|
<div className='grow overflow-y-auto relative'> |
|
{ |
|
shouldShowDataSourceTypeList && ( |
|
<div className={s.stepHeader}>{t('datasetCreation.steps.one')}</div> |
|
) |
|
} |
|
<div className={s.form}> |
|
{ |
|
shouldShowDataSourceTypeList && ( |
|
<div className='flex items-center mb-8 flex-wrap gap-y-4'> |
|
<div |
|
className={cn( |
|
s.dataSourceItem, |
|
dataSourceType === DataSourceType.FILE && s.active, |
|
dataSourceTypeDisable && dataSourceType !== DataSourceType.FILE && s.disabled, |
|
)} |
|
onClick={() => { |
|
if (dataSourceTypeDisable) |
|
return |
|
changeType(DataSourceType.FILE) |
|
hideFilePreview() |
|
hideNotionPagePreview() |
|
}} |
|
> |
|
<span className={cn(s.datasetIcon)} /> |
|
{t('datasetCreation.stepOne.dataSourceType.file')} |
|
</div> |
|
<div |
|
className={cn( |
|
s.dataSourceItem, |
|
dataSourceType === DataSourceType.NOTION && s.active, |
|
dataSourceTypeDisable && dataSourceType !== DataSourceType.NOTION && s.disabled, |
|
)} |
|
onClick={() => { |
|
if (dataSourceTypeDisable) |
|
return |
|
changeType(DataSourceType.NOTION) |
|
hideFilePreview() |
|
hideNotionPagePreview() |
|
}} |
|
> |
|
<span className={cn(s.datasetIcon, s.notion)} /> |
|
{t('datasetCreation.stepOne.dataSourceType.notion')} |
|
</div> |
|
<div |
|
className={cn( |
|
s.dataSourceItem, |
|
dataSourceType === DataSourceType.WEB && s.active, |
|
dataSourceTypeDisable && dataSourceType !== DataSourceType.WEB && s.disabled, |
|
)} |
|
onClick={() => changeType(DataSourceType.WEB)} |
|
> |
|
<span className={cn(s.datasetIcon, s.web)} /> |
|
{t('datasetCreation.stepOne.dataSourceType.web')} |
|
</div> |
|
</div> |
|
) |
|
} |
|
{dataSourceType === DataSourceType.FILE && ( |
|
<> |
|
<FileUploader |
|
fileList={files} |
|
titleClassName={!shouldShowDataSourceTypeList ? 'mt-[30px] !mb-[44px] !text-lg !font-semibold !text-gray-900' : undefined} |
|
prepareFileList={updateFileList} |
|
onFileListUpdate={updateFileList} |
|
onFileUpdate={updateFile} |
|
onPreview={updateCurrentFile} |
|
notSupportBatchUpload={notSupportBatchUpload} |
|
/> |
|
{isShowVectorSpaceFull && ( |
|
<div className='max-w-[640px] mb-4'> |
|
<VectorSpaceFull /> |
|
</div> |
|
)} |
|
<Button disabled={nextDisabled} className={s.submitButton} variant='primary' onClick={onStepChange}>{t('datasetCreation.stepOne.button')}</Button> |
|
</> |
|
)} |
|
{dataSourceType === DataSourceType.NOTION && ( |
|
<> |
|
{!hasConnection && <NotionConnector onSetting={onSetting} />} |
|
{hasConnection && ( |
|
<> |
|
<div className='mb-8 w-[640px]'> |
|
<NotionPageSelector |
|
value={notionPages.map(page => page.page_id)} |
|
onSelect={updateNotionPages} |
|
onPreview={updateCurrentPage} |
|
/> |
|
</div> |
|
{isShowVectorSpaceFull && ( |
|
<div className='max-w-[640px] mb-4'> |
|
<VectorSpaceFull /> |
|
</div> |
|
)} |
|
<Button disabled={isShowVectorSpaceFull || !notionPages.length} className={s.submitButton} variant='primary' onClick={onStepChange}>{t('datasetCreation.stepOne.button')}</Button> |
|
</> |
|
)} |
|
</> |
|
)} |
|
{dataSourceType === DataSourceType.WEB && ( |
|
<> |
|
<div className={cn('mb-8 w-[640px]', !shouldShowDataSourceTypeList && 'mt-12')}> |
|
<Website |
|
onPreview={setCurrentWebsite} |
|
checkedCrawlResult={websitePages} |
|
onCheckedCrawlResultChange={updateWebsitePages} |
|
onCrawlProviderChange={onWebsiteCrawlProviderChange} |
|
onJobIdChange={onWebsiteCrawlJobIdChange} |
|
crawlOptions={crawlOptions} |
|
onCrawlOptionsChange={onCrawlOptionsChange} |
|
/> |
|
</div> |
|
{isShowVectorSpaceFull && ( |
|
<div className='max-w-[640px] mb-4'> |
|
<VectorSpaceFull /> |
|
</div> |
|
)} |
|
<Button disabled={isShowVectorSpaceFull || !websitePages.length} className={s.submitButton} variant='primary' onClick={onStepChange}>{t('datasetCreation.stepOne.button')}</Button> |
|
</> |
|
)} |
|
{!datasetId && ( |
|
<> |
|
<div className={s.dividerLine} /> |
|
<div onClick={modalShowHandle} className={s.OtherCreationOption}>{t('datasetCreation.stepOne.emptyDatasetCreation')}</div> |
|
</> |
|
)} |
|
</div> |
|
<EmptyDatasetCreationModal show={showModal} onHide={modalCloseHandle} /> |
|
</div> |
|
{currentFile && <FilePreview file={currentFile} hidePreview={hideFilePreview} />} |
|
{currentNotionPage && <NotionPagePreview currentPage={currentNotionPage} hidePreview={hideNotionPagePreview} />} |
|
{currentWebsite && <WebsitePreview payload={currentWebsite} hidePreview={hideWebsitePreview} />} |
|
</div> |
|
) |
|
} |
|
|
|
export default StepOne |
|
|