| import { useCallback, useEffect, useMemo, useState } from 'react' | import { useCallback, useEffect, useMemo, useState } from 'react' | ||||
| import { useTranslation } from 'react-i18next' | |||||
| import { useContext } from 'use-context-selector' | |||||
| import useSWR from 'swr' | import useSWR from 'swr' | ||||
| import cn from 'classnames' | import cn from 'classnames' | ||||
| import s from './base.module.css' | import s from './base.module.css' | ||||
| import { preImportNotionPages } from '@/service/datasets' | import { preImportNotionPages } from '@/service/datasets' | ||||
| import { NotionConnector } from '@/app/components/datasets/create/step-one' | import { NotionConnector } from '@/app/components/datasets/create/step-one' | ||||
| import type { DataSourceNotionPageMap, DataSourceNotionWorkspace, NotionPage } from '@/models/common' | import type { DataSourceNotionPageMap, DataSourceNotionWorkspace, NotionPage } from '@/models/common' | ||||
| import { ToastContext } from '@/app/components/base/toast' | |||||
| import { useModalContext } from '@/context/modal-context' | import { useModalContext } from '@/context/modal-context' | ||||
| type NotionPageSelectorProps = { | type NotionPageSelectorProps = { | ||||
| previewPageId?: string | previewPageId?: string | ||||
| onPreview?: (selectedPage: NotionPage) => void | onPreview?: (selectedPage: NotionPage) => void | ||||
| datasetId?: string | datasetId?: string | ||||
| countLimit: number | |||||
| countUsed: number | |||||
| } | } | ||||
| const NotionPageSelector = ({ | const NotionPageSelector = ({ | ||||
| previewPageId, | previewPageId, | ||||
| onPreview, | onPreview, | ||||
| datasetId = '', | datasetId = '', | ||||
| countLimit, | |||||
| countUsed, | |||||
| }: NotionPageSelectorProps) => { | }: NotionPageSelectorProps) => { | ||||
| const { t } = useTranslation() | |||||
| const { notify } = useContext(ToastContext) | |||||
| const { data, mutate } = useSWR({ url: '/notion/pre-import/pages', datasetId }, preImportNotionPages) | const { data, mutate } = useSWR({ url: '/notion/pre-import/pages', datasetId }, preImportNotionPages) | ||||
| const [prevData, setPrevData] = useState(data) | const [prevData, setPrevData] = useState(data) | ||||
| const [searchValue, setSearchValue] = useState('') | const [searchValue, setSearchValue] = useState('') | ||||
| }, []) | }, []) | ||||
| const handleSelecPages = (newSelectedPagesId: Set<string>) => { | const handleSelecPages = (newSelectedPagesId: Set<string>) => { | ||||
| const selectedPages = Array.from(newSelectedPagesId).map(pageId => getPagesMapAndSelectedPagesId[0][pageId]) | const selectedPages = Array.from(newSelectedPagesId).map(pageId => getPagesMapAndSelectedPagesId[0][pageId]) | ||||
| if (selectedPages.length > countLimit - countUsed) { | |||||
| notify({ type: 'error', message: t('datasetCreation.stepOne.overCountLimit', { countLimit }) }) | |||||
| return false | |||||
| } | |||||
| setSelectedPagesId(new Set(Array.from(newSelectedPagesId))) | setSelectedPagesId(new Set(Array.from(newSelectedPagesId))) | ||||
| onSelect(selectedPages) | onSelect(selectedPages) | ||||
| } | } |
| 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 | ||||
| countLimit: number | |||||
| countUsed: number | |||||
| } | } | ||||
| const ACCEPTS = [ | const ACCEPTS = [ | ||||
| onFileUpdate, | onFileUpdate, | ||||
| onFileListUpdate, | onFileListUpdate, | ||||
| onPreview, | onPreview, | ||||
| countLimit, | |||||
| countUsed, | |||||
| }: IFileUploaderProps) => { | }: IFileUploaderProps) => { | ||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const { notify } = useContext(ToastContext) | const { notify } = useContext(ToastContext) | ||||
| const initialUpload = useCallback((files: File[]) => { | const initialUpload = useCallback((files: File[]) => { | ||||
| if (!files.length) | if (!files.length) | ||||
| return false | return false | ||||
| if (files.length > countLimit - countUsed) { | |||||
| notify({ type: 'error', message: t('datasetCreation.stepOne.overCountLimit', { countLimit }) }) | |||||
| return false | |||||
| } | |||||
| const preparedFiles = files.map((file, index) => ({ | const preparedFiles = files.map((file, index) => ({ | ||||
| fileID: `file${index}-${Date.now()}`, | fileID: `file${index}-${Date.now()}`, | ||||
| file, | file, |
| 'use client' | 'use client' | ||||
| import React, { useMemo, useState } from 'react' | import React, { useMemo, useState } from 'react' | ||||
| import useSWR from 'swr' | |||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import cn from 'classnames' | import cn from 'classnames' | ||||
| import FilePreview from '../file-preview' | import FilePreview from '../file-preview' | ||||
| import Button from '@/app/components/base/button' | import Button from '@/app/components/base/button' | ||||
| import { NotionPageSelector } from '@/app/components/base/notion-page-selector' | import { NotionPageSelector } from '@/app/components/base/notion-page-selector' | ||||
| import { useDatasetDetailContext } from '@/context/dataset-detail' | import { useDatasetDetailContext } from '@/context/dataset-detail' | ||||
| import { fetchDocumentsLimit } from '@/service/common' | |||||
| import { useProviderContext } from '@/context/provider-context' | import { useProviderContext } from '@/context/provider-context' | ||||
| import VectorSpaceFull from '@/app/components/billing/vector-space-full' | import VectorSpaceFull from '@/app/components/billing/vector-space-full' | ||||
| notionPages = [], | notionPages = [], | ||||
| updateNotionPages, | updateNotionPages, | ||||
| }: IStepOneProps) => { | }: IStepOneProps) => { | ||||
| const { data: limitsData } = useSWR('/datasets/limit', fetchDocumentsLimit) | |||||
| const { dataset } = useDatasetDetailContext() | const { dataset } = useDatasetDetailContext() | ||||
| const [showModal, setShowModal] = useState(false) | const [showModal, setShowModal] = useState(false) | ||||
| const [currentFile, setCurrentFile] = useState<File | undefined>() | const [currentFile, setCurrentFile] = useState<File | undefined>() | ||||
| </div> | </div> | ||||
| ) | ) | ||||
| } | } | ||||
| {dataSourceType === DataSourceType.FILE && limitsData && ( | |||||
| {dataSourceType === DataSourceType.FILE && ( | |||||
| <> | <> | ||||
| <FileUploader | <FileUploader | ||||
| fileList={files} | fileList={files} | ||||
| onFileListUpdate={updateFileList} | onFileListUpdate={updateFileList} | ||||
| onFileUpdate={updateFile} | onFileUpdate={updateFile} | ||||
| onPreview={updateCurrentFile} | onPreview={updateCurrentFile} | ||||
| countLimit={limitsData.documents_limit} | |||||
| countUsed={limitsData.documents_count} | |||||
| /> | /> | ||||
| {isShowVectorSpaceFull && ( | {isShowVectorSpaceFull && ( | ||||
| <div className='max-w-[640px] mb-4'> | <div className='max-w-[640px] mb-4'> | ||||
| {dataSourceType === DataSourceType.NOTION && ( | {dataSourceType === DataSourceType.NOTION && ( | ||||
| <> | <> | ||||
| {!hasConnection && <NotionConnector onSetting={onSetting} />} | {!hasConnection && <NotionConnector onSetting={onSetting} />} | ||||
| {hasConnection && limitsData && ( | |||||
| {hasConnection && ( | |||||
| <> | <> | ||||
| <div className='mb-8 w-[640px]'> | <div className='mb-8 w-[640px]'> | ||||
| <NotionPageSelector | <NotionPageSelector | ||||
| value={notionPages.map(page => page.page_id)} | value={notionPages.map(page => page.page_id)} | ||||
| onSelect={updateNotionPages} | onSelect={updateNotionPages} | ||||
| onPreview={updateCurrentPage} | onPreview={updateCurrentPage} | ||||
| countLimit={limitsData.documents_limit} | |||||
| countUsed={limitsData.documents_count} | |||||
| /> | /> | ||||
| </div> | </div> | ||||
| {isShowVectorSpaceFull && ( | {isShowVectorSpaceFull && ( |
| confirmButton: 'Create', | confirmButton: 'Create', | ||||
| failed: 'Creation failed', | failed: 'Creation failed', | ||||
| }, | }, | ||||
| overCountLimit: 'All your documents have overed limit {{countLimit}}.', | |||||
| }, | }, | ||||
| stepTwo: { | stepTwo: { | ||||
| segmentation: 'Chunk settings', | segmentation: 'Chunk settings', |
| confirmButton: '创建', | confirmButton: '创建', | ||||
| failed: '创建失败', | failed: '创建失败', | ||||
| }, | }, | ||||
| overCountLimit: '您的文件总数已超出限制 {{countLimit}}。', | |||||
| }, | }, | ||||
| stepTwo: { | stepTwo: { | ||||
| segmentation: '分段设置', | segmentation: '分段设置', |
| image_file_size_limit?: number | string | image_file_size_limit?: number | string | ||||
| } | } | ||||
| export type DocumentsLimitResponse = { | |||||
| documents_count: number | |||||
| documents_limit: number | |||||
| } | |||||
| export type InvitationResult = { | export type InvitationResult = { | ||||
| status: 'success' | status: 'success' | ||||
| email: string | email: string |
| CodeBasedExtension, | CodeBasedExtension, | ||||
| CommonResponse, | CommonResponse, | ||||
| DataSourceNotion, | DataSourceNotion, | ||||
| DocumentsLimitResponse, | |||||
| FileUploadConfigResponse, | FileUploadConfigResponse, | ||||
| ICurrentWorkspace, | ICurrentWorkspace, | ||||
| IWorkspace, | IWorkspace, | ||||
| return get<FileUploadConfigResponse>(url) | return get<FileUploadConfigResponse>(url) | ||||
| } | } | ||||
| export const fetchDocumentsLimit: Fetcher<DocumentsLimitResponse, string> = (url) => { | |||||
| return get<DocumentsLimitResponse>(url) | |||||
| } | |||||
| export const fetchFreeQuotaVerify: Fetcher<{ result: string; flag: boolean; reason: string }, string> = (url) => { | export const fetchFreeQuotaVerify: Fetcher<{ result: string; flag: boolean; reason: string }, string> = (url) => { | ||||
| return get(url) as Promise<{ result: string; flag: boolean; reason: string }> | return get(url) as Promise<{ result: string; flag: boolean; reason: string }> | ||||
| } | } |