| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 | 
							- 'use client'
 
- import type { FC } from 'react'
 
- import React, { useState } from 'react'
 
- import useSWR from 'swr'
 
- import { ArrowLeftIcon } from '@heroicons/react/24/solid'
 
- import { createContext, useContext } from 'use-context-selector'
 
- import { useTranslation } from 'react-i18next'
 
- import { useRouter } from 'next/navigation'
 
- import { omit } from 'lodash-es'
 
- import { OperationAction, StatusItem } from '../list'
 
- import s from '../style.module.css'
 
- import Completed from './completed'
 
- import Embedding from './embedding'
 
- import Metadata from './metadata'
 
- import SegmentAdd, { ProcessStatus } from './segment-add'
 
- import BatchModal from './batch-modal'
 
- import style from './style.module.css'
 
- import cn from '@/utils/classnames'
 
- import Divider from '@/app/components/base/divider'
 
- 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 } 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'
 
- export const DocumentContext = createContext<{ datasetId?: string; documentId?: string; docForm: string }>({ docForm: '' })
 
- type DocumentTitleProps = {
 
-   extension?: string
 
-   name?: string
 
-   iconCls?: string
 
-   textCls?: string
 
-   wrapperCls?: string
 
- }
 
- export const DocumentTitle: FC<DocumentTitleProps> = ({ extension, name, iconCls, textCls, wrapperCls }) => {
 
-   const localExtension = extension?.toLowerCase() || name?.split('.')?.pop()?.toLowerCase()
 
-   return <div className={cn('flex items-center justify-start flex-1', wrapperCls)}>
 
-     <div className={cn(s[`${localExtension || 'txt'}Icon`], style.titleIcon, iconCls)}></div>
 
-     <span className={cn('font-semibold text-lg text-gray-900 ml-1', textCls)}> {name || '--'}</span>
 
-   </div>
 
- }
 
- type Props = {
 
-   datasetId: string
 
-   documentId: string
 
- }
 
- const DocumentDetail: FC<Props> = ({ datasetId, documentId }) => {
 
-   const router = useRouter()
 
-   const { t } = useTranslation()
 
-   const media = useBreakpoints()
 
-   const isMobile = media === MediaType.mobile
 
-   const { notify } = useContext(ToastContext)
 
-   const { dataset } = useDatasetDetailContext()
 
-   const embeddingAvailable = !!dataset?.embedding_available
 
-   const [showMetadata, setShowMetadata] = useState(!isMobile)
 
-   const [newSegmentModalVisible, setNewSegmentModalVisible] = useState(false)
 
-   const [batchModalVisible, setBatchModalVisible] = useState(false)
 
-   const [importStatus, setImportStatus] = useState<ProcessStatus | string>()
 
-   const showNewSegmentModal = () => setNewSegmentModalVisible(true)
 
-   const showBatchModal = () => setBatchModalVisible(true)
 
-   const hideBatchModal = () => setBatchModalVisible(false)
 
-   const resetProcessStatus = () => setImportStatus('')
 
-   const checkProcess = async (jobID: string) => {
 
-     try {
 
-       const res = await checkSegmentBatchImportProgress({ jobID })
 
-       setImportStatus(res.job_status)
 
-       if (res.job_status === ProcessStatus.WAITING || res.job_status === ProcessStatus.PROCESSING)
 
-         setTimeout(() => checkProcess(res.job_id), 2500)
 
-       if (res.job_status === ProcessStatus.ERROR)
 
-         notify({ type: 'error', message: `${t('datasetDocuments.list.batchModal.runError')}` })
 
-     }
 
-     catch (e: any) {
 
-       notify({ type: 'error', message: `${t('datasetDocuments.list.batchModal.runError')}${'message' in e ? `: ${e.message}` : ''}` })
 
-     }
 
-   }
 
-   const runBatch = async (csv: File) => {
 
-     const formData = new FormData()
 
-     formData.append('file', csv)
 
-     try {
 
-       const res = await segmentBatchImport({
 
-         url: `/datasets/${datasetId}/documents/${documentId}/segments/batch_import`,
 
-         body: formData,
 
-       })
 
-       setImportStatus(res.job_status)
 
-       checkProcess(res.job_id)
 
-     }
 
-     catch (e: any) {
 
-       notify({ type: 'error', message: `${t('datasetDocuments.list.batchModal.runError')}${'message' in e ? `: ${e.message}` : ''}` })
 
-     }
 
-   }
 
-   const { data: documentDetail, error, mutate: detailMutate } = useSWR({
 
-     action: 'fetchDocumentDetail',
 
-     datasetId,
 
-     documentId,
 
-     params: { metadata: 'without' as MetadataType },
 
-   }, apiParams => fetchDocumentDetail(omit(apiParams, 'action')))
 
-   const { data: documentMetadata, error: metadataErr, mutate: metadataMutate } = useSWR({
 
-     action: 'fetchDocumentDetail',
 
-     datasetId,
 
-     documentId,
 
-     params: { metadata: 'only' as MetadataType },
 
-   }, apiParams => fetchDocumentDetail(omit(apiParams, 'action')),
 
-   )
 
-   const backToPrev = () => {
 
-     router.push(`/datasets/${datasetId}/documents`)
 
-   }
 
-   const isDetailLoading = !documentDetail && !error
 
-   const isMetadataLoading = !documentMetadata && !metadataErr
 
-   const embedding = ['queuing', 'indexing', 'paused'].includes((documentDetail?.display_status || '').toLowerCase())
 
-   const handleOperate = (operateName?: string) => {
 
-     if (operateName === 'delete')
 
-       backToPrev()
 
-     else
 
-       detailMutate()
 
-   }
 
-   return (
 
-     <DocumentContext.Provider value={{ datasetId, documentId, docForm: documentDetail?.doc_form || '' }}>
 
-       <div className='flex flex-col h-full'>
 
-         <div className='flex min-h-16 border-b-gray-100 border-b items-center p-4 justify-between flex-wrap gap-y-2'>
 
-           <div onClick={backToPrev} className={'shrink-0 rounded-full w-8 h-8 flex justify-center items-center border-gray-100 cursor-pointer border hover:border-gray-300 shadow-[0px_12px_16px_-4px_rgba(16,24,40,0.08),0px_4px_6px_-2px_rgba(16,24,40,0.03)]'}>
 
-             <ArrowLeftIcon className='text-primary-600 fill-current stroke-current h-4 w-4' />
 
-           </div>
 
-           <Divider className='!h-4' type='vertical' />
 
-           <DocumentTitle extension={documentDetail?.data_source_info?.upload_file?.extension} name={documentDetail?.name} />
 
-           <div className='flex items-center flex-wrap gap-y-2'>
 
-             <StatusItem status={documentDetail?.display_status || 'available'} scene='detail' errorMessage={documentDetail?.error || ''} />
 
-             {embeddingAvailable && documentDetail && !documentDetail.archived && (
 
-               <SegmentAdd
 
-                 importStatus={importStatus}
 
-                 clearProcessStatus={resetProcessStatus}
 
-                 showNewSegmentModal={showNewSegmentModal}
 
-                 showBatchModal={showBatchModal}
 
-               />
 
-             )}
 
-             <OperationAction
 
-               scene='detail'
 
-               embeddingAvailable={embeddingAvailable}
 
-               detail={{
 
-                 name: documentDetail?.name || '',
 
-                 enabled: documentDetail?.enabled || false,
 
-                 archived: documentDetail?.archived || false,
 
-                 id: documentId,
 
-                 data_source_type: documentDetail?.data_source_type || '',
 
-                 doc_form: documentDetail?.doc_form || '',
 
-               }}
 
-               datasetId={datasetId}
 
-               onUpdate={handleOperate}
 
-               className='!w-[216px]'
 
-             />
 
-             <button
 
-               className={cn(style.layoutRightIcon, showMetadata ? style.iconShow : style.iconClose)}
 
-               onClick={() => setShowMetadata(!showMetadata)}
 
-             />
 
-           </div>
 
-         </div>
 
-         <div className='flex flex-row flex-1' style={{ height: 'calc(100% - 4rem)' }}>
 
-           {isDetailLoading
 
-             ? <Loading type='app' />
 
-             : <div className={`h-full w-full flex flex-col ${embedding ? 'px-6 py-3 sm:py-12 sm:px-16' : 'pb-[30px] pt-3 px-6'}`}>
 
-               {embedding
 
-                 ? <Embedding detail={documentDetail} detailUpdate={detailMutate} />
 
-                 : <Completed
 
-                   embeddingAvailable={embeddingAvailable}
 
-                   showNewSegmentModal={newSegmentModalVisible}
 
-                   onNewSegmentModalChange={setNewSegmentModalVisible}
 
-                   importStatus={importStatus}
 
-                   archived={documentDetail?.archived}
 
-                 />
 
-               }
 
-             </div>
 
-           }
 
-           <FloatRightContainer showClose isOpen={showMetadata} onClose={() => setShowMetadata(false)} isMobile={isMobile} panelClassname='!justify-start' footer={null}>
 
-             <Metadata
 
-               docDetail={{ ...documentDetail, ...documentMetadata, doc_type: documentMetadata?.doc_type === 'others' ? '' : documentMetadata?.doc_type } as any}
 
-               loading={isMetadataLoading}
 
-               onUpdate={metadataMutate}
 
-             />
 
-           </FloatRightContainer>
 
-         </div>
 
-         <BatchModal
 
-           isShow={batchModalVisible}
 
-           onCancel={hideBatchModal}
 
-           onConfirm={runBatch}
 
-           docForm={documentDetail?.doc_form as DocForm}
 
-         />
 
-       </div>
 
-     </DocumentContext.Provider>
 
-   )
 
- }
 
- export default DocumentDetail
 
 
  |