diff --git a/web/app/components/base/file-uploader/file-type-icon.tsx b/web/app/components/base/file-uploader/file-type-icon.tsx index ed4cdde7e7..193a630dee 100644 --- a/web/app/components/base/file-uploader/file-type-icon.tsx +++ b/web/app/components/base/file-uploader/file-type-icon.tsx @@ -82,12 +82,9 @@ const FileTypeIcon = ({ size = 'sm', className, }: FileTypeIconProps) => { - const Icon = FILE_TYPE_ICON_MAP[type].component + const Icon = FILE_TYPE_ICON_MAP[type].component || FileAppearanceTypeEnum.custom const color = FILE_TYPE_ICON_MAP[type].color - if (!Icon) - return null - return } diff --git a/web/app/components/datasets/common/document-picker/document-list.tsx b/web/app/components/datasets/common/document-picker/document-list.tsx new file mode 100644 index 0000000000..3e320d7507 --- /dev/null +++ b/web/app/components/datasets/common/document-picker/document-list.tsx @@ -0,0 +1,42 @@ +'use client' +import type { FC } from 'react' +import React, { useCallback } from 'react' +import FileIcon from '../document-file-icon' +import cn from '@/utils/classnames' +import type { DocumentItem } from '@/models/datasets' + +type Props = { + className?: string + list: DocumentItem[] + onChange: (value: DocumentItem) => void +} + +const DocumentList: FC = ({ + className, + list, + onChange, +}) => { + const handleChange = useCallback((item: DocumentItem) => { + return () => onChange(item) + }, [onChange]) + + return ( +
+ {list.map((item) => { + const { id, name, extension } = item + return ( +
+ +
{name}
+
+ ) + })} +
+ ) +} + +export default React.memo(DocumentList) diff --git a/web/app/components/datasets/common/document-picker/index.tsx b/web/app/components/datasets/common/document-picker/index.tsx index 0f7f0aa69a..cd95314d28 100644 --- a/web/app/components/datasets/common/document-picker/index.tsx +++ b/web/app/components/datasets/common/document-picker/index.tsx @@ -1,11 +1,12 @@ 'use client' import type { FC } from 'react' -import React, { useState } from 'react' +import React, { useCallback, useState } from 'react' import { useBoolean } from 'ahooks' -import { RiArrowDownSLine, RiArrowUpSLine } from '@remixicon/react' +import { RiArrowDownSLine } from '@remixicon/react' import { useTranslation } from 'react-i18next' import FileIcon from '../document-file-icon' -import type { ParentMode, SimpleDocumentDetail } from '@/models/datasets' +import DocumentList from './document-list' +import type { DocumentItem, ParentMode, SimpleDocumentDetail } from '@/models/datasets' import { ProcessMode } from '@/models/datasets' import { PortalToFollowElem, @@ -59,7 +60,12 @@ const DocumentPicker: FC = ({ set: setOpen, toggle: togglePopup, }] = useBoolean(false) - const ArrowIcon = open ? RiArrowDownSLine : RiArrowUpSLine + const ArrowIcon = RiArrowDownSLine + + const handleChange = useCallback(({ id }: DocumentItem) => { + onChange(documentsList?.find(item => item.id === id) as SimpleDocumentDetail) + setOpen(false) + }, [documentsList, onChange, setOpen]) return ( = ({ -
{documentsList ? ( -
- {documentsList.map(item => ( -
{ - onChange(item) - setOpen(false) - } - } - > - -
{item.name}
-
- ))} -
+ ({ + id: d.id, + name: d.name, + extension: d.data_source_detail_dict?.upload_file.extension || '', + }))} + onChange={handleChange} + /> ) : (
diff --git a/web/app/components/datasets/common/document-picker/preview-document-picker.tsx b/web/app/components/datasets/common/document-picker/preview-document-picker.tsx new file mode 100644 index 0000000000..856e90a28d --- /dev/null +++ b/web/app/components/datasets/common/document-picker/preview-document-picker.tsx @@ -0,0 +1,82 @@ +'use client' +import type { FC } from 'react' +import React, { useCallback } from 'react' +import { useBoolean } from 'ahooks' +import { RiArrowDownSLine } from '@remixicon/react' +import { useTranslation } from 'react-i18next' +import FileIcon from '../document-file-icon' +import DocumentList from './document-list' +import { + PortalToFollowElem, + PortalToFollowElemContent, + PortalToFollowElemTrigger, +} from '@/app/components/base/portal-to-follow-elem' +import cn from '@/utils/classnames' +import Loading from '@/app/components/base/loading' +import type { DocumentItem } from '@/models/datasets' + +type Props = { + className?: string + value: DocumentItem + files: DocumentItem[] + onChange: (value: DocumentItem) => void +} + +const PreviewDocumentPicker: FC = ({ + className, + value, + files, + onChange, +}) => { + const { t } = useTranslation() + const { name, extension } = value + + const [open, { + set: setOpen, + toggle: togglePopup, + }] = useBoolean(false) + const ArrowIcon = RiArrowDownSLine + + const handleChange = useCallback((item: DocumentItem) => { + onChange(item) + setOpen(false) + }, [onChange, setOpen]) + + return ( + + +
+ +
+
+ {name || '--'} + +
+
+
+
+ +
+ {files?.length > 1 &&
{t('dataset.preprocessDocument', { num: files.length })}
} + {files?.length > 0 + ? ( + + ) + : (
+ +
)} +
+ +
+
+ ) +} +export default React.memo(PreviewDocumentPicker) diff --git a/web/app/components/datasets/documents/detail/index.tsx b/web/app/components/datasets/documents/detail/index.tsx index 7d2ee9fa13..25fe7f5a8f 100644 --- a/web/app/components/datasets/documents/detail/index.tsx +++ b/web/app/components/datasets/documents/detail/index.tsx @@ -9,6 +9,7 @@ import { omit } from 'lodash-es' import { RiArrowLeftLine, RiLayoutRight2Line } from '@remixicon/react' import { OperationAction, StatusItem } from '../list' import DocumentPicker from '../../common/document-picker' +import PreviewDocumentPicker from '../../common/document-picker/preview-document-picker' import Completed from './completed' import Embedding from './embedding' import Metadata from './metadata' @@ -21,7 +22,7 @@ import Loading from '@/app/components/base/loading' import type { MetadataType } from '@/service/datasets' import { checkSegmentBatchImportProgress, fetchDocumentDetail, segmentBatchImport } from '@/service/datasets' import { ToastContext } from '@/app/components/base/toast' -import type { DocForm, ParentMode, ProcessMode } from '@/models/datasets' +import type { DocForm, DocumentItem, ParentMode, ProcessMode } from '@/models/datasets' import { useDatasetDetailContext } from '@/context/dataset-detail' import FloatRightContainer from '@/app/components/base/float-right-container' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' @@ -52,6 +53,21 @@ type DocumentTitleProps = { } export const DocumentTitle: FC = ({ datasetId, extension, name, processMode, parent_mode, wrapperCls }) => { + const testPreviewFiles = [ + { + id: '1', + name: 'EOS R3', + extension: 'pdf', + }, + { + id: '2', + name: 'EOS R5', + extension: 'pdf', + }, + ] + + const [previewFile, setPreviewFile] = useState(testPreviewFiles[0]) + return (
{/* // todo: handle file change */} @@ -65,6 +81,12 @@ export const DocumentTitle: FC = ({ datasetId, extension, na }} onChange={(doc) => { console.log(doc) }} /> + {/* todo: another document picker demo */} +
) } diff --git a/web/i18n/en-US/dataset.ts b/web/i18n/en-US/dataset.ts index 75eda76a24..32aacc637c 100644 --- a/web/i18n/en-US/dataset.ts +++ b/web/i18n/en-US/dataset.ts @@ -158,6 +158,7 @@ const translation = { delete: 'Delete', cancel: 'Cancel', }, + preprocessDocument: '{{num}} Preprocess Documents', } export default translation diff --git a/web/i18n/zh-Hans/dataset.ts b/web/i18n/zh-Hans/dataset.ts index 1d4897a69f..94db7713c7 100644 --- a/web/i18n/zh-Hans/dataset.ts +++ b/web/i18n/zh-Hans/dataset.ts @@ -158,6 +158,7 @@ const translation = { delete: '删除', cancel: '取消', }, + preprocessDocument: '{{num}} 个预处理文档', } export default translation diff --git a/web/models/datasets.ts b/web/models/datasets.ts index 3aea56936a..f71c314995 100644 --- a/web/models/datasets.ts +++ b/web/models/datasets.ts @@ -102,6 +102,12 @@ export type CustomFile = File & { created_at?: number } +export type DocumentItem = { + id: string + name: string + extension: string +} + export type CrawlOptions = { crawl_sub_pages: boolean only_main_content: boolean