mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-15 09:06:02 +08:00
fix: fix document list overlap and optimize document list fetching (#15377)
This commit is contained in:
parent
269ba6add9
commit
2cf0cb471f
@ -23,7 +23,7 @@ import FloatRightContainer from '@/app/components/base/float-right-container'
|
|||||||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||||
import { LayoutRight2LineMod } from '@/app/components/base/icons/src/public/knowledge'
|
import { LayoutRight2LineMod } from '@/app/components/base/icons/src/public/knowledge'
|
||||||
import { useCheckSegmentBatchImportProgress, useChildSegmentListKey, useSegmentBatchImport, useSegmentListKey } from '@/service/knowledge/use-segment'
|
import { useCheckSegmentBatchImportProgress, useChildSegmentListKey, useSegmentBatchImport, useSegmentListKey } from '@/service/knowledge/use-segment'
|
||||||
import { useDocumentDetail, useDocumentMetadata } from '@/service/knowledge/use-document'
|
import { useDocumentDetail, useDocumentMetadata, useInvalidDocumentList } from '@/service/knowledge/use-document'
|
||||||
import { useInvalid } from '@/service/use-base'
|
import { useInvalid } from '@/service/use-base'
|
||||||
|
|
||||||
type DocumentContextValue = {
|
type DocumentContextValue = {
|
||||||
@ -152,17 +152,22 @@ const DocumentDetail: FC<Props> = ({ datasetId, documentId }) => {
|
|||||||
|
|
||||||
const invalidChunkList = useInvalid(useSegmentListKey)
|
const invalidChunkList = useInvalid(useSegmentListKey)
|
||||||
const invalidChildChunkList = useInvalid(useChildSegmentListKey)
|
const invalidChildChunkList = useInvalid(useChildSegmentListKey)
|
||||||
|
const invalidDocumentList = useInvalidDocumentList(datasetId)
|
||||||
|
|
||||||
const handleOperate = (operateName?: string) => {
|
const handleOperate = (operateName?: string) => {
|
||||||
|
invalidDocumentList()
|
||||||
if (operateName === 'delete') {
|
if (operateName === 'delete') {
|
||||||
backToPrev()
|
backToPrev()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
detailMutate()
|
detailMutate()
|
||||||
setTimeout(() => {
|
// If operation is not rename, refresh the chunk list after 5 seconds
|
||||||
invalidChunkList()
|
if (operateName) {
|
||||||
invalidChildChunkList()
|
setTimeout(() => {
|
||||||
}, 5000)
|
invalidChunkList()
|
||||||
|
invalidChildChunkList()
|
||||||
|
}, 5000)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import useSWR from 'swr'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { useDebounce, useDebounceFn } from 'ahooks'
|
import { useDebounce, useDebounceFn } from 'ahooks'
|
||||||
import { groupBy, omit } from 'lodash-es'
|
import { groupBy } from 'lodash-es'
|
||||||
import { PlusIcon } from '@heroicons/react/24/solid'
|
import { PlusIcon } from '@heroicons/react/24/solid'
|
||||||
import { RiExternalLinkLine } from '@remixicon/react'
|
import { RiExternalLinkLine } from '@remixicon/react'
|
||||||
import AutoDisabledDocument from '../common/document-status-with-action/auto-disabled-document'
|
import AutoDisabledDocument from '../common/document-status-with-action/auto-disabled-document'
|
||||||
@ -15,16 +14,16 @@ import Loading from '@/app/components/base/loading'
|
|||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
import Input from '@/app/components/base/input'
|
import Input from '@/app/components/base/input'
|
||||||
import { get } from '@/service/base'
|
import { get } from '@/service/base'
|
||||||
import { createDocument, fetchDocuments } from '@/service/datasets'
|
import { createDocument } from '@/service/datasets'
|
||||||
import { useDatasetDetailContext } from '@/context/dataset-detail'
|
import { useDatasetDetailContext } from '@/context/dataset-detail'
|
||||||
import { NotionPageSelectorModal } from '@/app/components/base/notion-page-selector'
|
import { NotionPageSelectorModal } from '@/app/components/base/notion-page-selector'
|
||||||
import type { NotionPage } from '@/models/common'
|
import type { NotionPage } from '@/models/common'
|
||||||
import type { CreateDocumentReq } from '@/models/datasets'
|
import type { CreateDocumentReq } from '@/models/datasets'
|
||||||
import { DataSourceType } from '@/models/datasets'
|
import { DataSourceType, ProcessMode } from '@/models/datasets'
|
||||||
import IndexFailed from '@/app/components/datasets/common/document-status-with-action/index-failed'
|
import IndexFailed from '@/app/components/datasets/common/document-status-with-action/index-failed'
|
||||||
import { useProviderContext } from '@/context/provider-context'
|
import { useProviderContext } from '@/context/provider-context'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import { useInvalidDocumentDetailKey } from '@/service/knowledge/use-document'
|
import { useDocumentList, useInvalidDocumentDetailKey, useInvalidDocumentList } from '@/service/knowledge/use-document'
|
||||||
import { useInvalid } from '@/service/use-base'
|
import { useInvalid } from '@/service/use-base'
|
||||||
import { useChildSegmentListKey, useSegmentListKey } from '@/service/knowledge/use-segment'
|
import { useChildSegmentListKey, useSegmentListKey } from '@/service/knowledge/use-segment'
|
||||||
|
|
||||||
@ -73,12 +72,12 @@ const EmptyElement: FC<{ canAdd: boolean; onClick: () => void; type?: 'upload' |
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IDocumentsProps {
|
type IDocumentsProps = {
|
||||||
datasetId: string
|
datasetId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetcher = (url: string) => get(url, {}, {})
|
export const fetcher = (url: string) => get(url, {}, {})
|
||||||
const DEFAULT_LIMIT = 15
|
const DEFAULT_LIMIT = 10
|
||||||
|
|
||||||
const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -99,33 +98,33 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
|||||||
|
|
||||||
const debouncedSearchValue = useDebounce(searchValue, { wait: 500 })
|
const debouncedSearchValue = useDebounce(searchValue, { wait: 500 })
|
||||||
|
|
||||||
const query = useMemo(() => {
|
const { data: documentsRes, isFetching: isListLoading } = useDocumentList({
|
||||||
return { page: currPage + 1, limit, keyword: debouncedSearchValue, fetch: isDataSourceNotion ? true : '' }
|
datasetId,
|
||||||
}, [currPage, debouncedSearchValue, isDataSourceNotion, limit])
|
query: {
|
||||||
|
page: currPage + 1,
|
||||||
const { data: documentsRes, mutate, isLoading: isListLoading } = useSWR(
|
limit,
|
||||||
{
|
keyword: debouncedSearchValue,
|
||||||
action: 'fetchDocuments',
|
|
||||||
datasetId,
|
|
||||||
params: query,
|
|
||||||
},
|
},
|
||||||
apiParams => fetchDocuments(omit(apiParams, 'action')),
|
refetchInterval: (isDataSourceNotion && timerCanRun) ? 2500 : 0,
|
||||||
{ refreshInterval: (isDataSourceNotion && timerCanRun) ? 2500 : 0 },
|
})
|
||||||
)
|
|
||||||
|
const invalidDocumentList = useInvalidDocumentList(datasetId)
|
||||||
|
|
||||||
const [isMuting, setIsMuting] = useState(false)
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isListLoading && isMuting)
|
if (documentsRes) {
|
||||||
setIsMuting(false)
|
const totalPages = Math.ceil(documentsRes.total / limit)
|
||||||
}, [isListLoading, isMuting])
|
if (totalPages < currPage + 1)
|
||||||
|
setCurrPage(totalPages === 0 ? 0 : totalPages - 1)
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [documentsRes])
|
||||||
|
|
||||||
const invalidDocumentDetail = useInvalidDocumentDetailKey()
|
const invalidDocumentDetail = useInvalidDocumentDetailKey()
|
||||||
const invalidChunkList = useInvalid(useSegmentListKey)
|
const invalidChunkList = useInvalid(useSegmentListKey)
|
||||||
const invalidChildChunkList = useInvalid(useChildSegmentListKey)
|
const invalidChildChunkList = useInvalid(useChildSegmentListKey)
|
||||||
|
|
||||||
const handleUpdate = useCallback(() => {
|
const handleUpdate = useCallback(() => {
|
||||||
setIsMuting(true)
|
invalidDocumentList()
|
||||||
mutate()
|
|
||||||
invalidDocumentDetail()
|
invalidDocumentDetail()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
invalidChunkList()
|
invalidChunkList()
|
||||||
@ -175,8 +174,6 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
|||||||
router.push(`/datasets/${datasetId}/documents/create`)
|
router.push(`/datasets/${datasetId}/documents/create`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const isLoading = isListLoading // !documentsRes && !error
|
|
||||||
|
|
||||||
const handleSaveNotionPageSelected = async (selectedPages: NotionPage[]) => {
|
const handleSaveNotionPageSelected = async (selectedPages: NotionPage[]) => {
|
||||||
const workspacesMap = groupBy(selectedPages, 'workspace_id')
|
const workspacesMap = groupBy(selectedPages, 'workspace_id')
|
||||||
const workspaces = Object.keys(workspacesMap).map((workspaceId) => {
|
const workspaces = Object.keys(workspacesMap).map((workspaceId) => {
|
||||||
@ -209,7 +206,7 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
|||||||
indexing_technique: dataset?.indexing_technique,
|
indexing_technique: dataset?.indexing_technique,
|
||||||
process_rule: {
|
process_rule: {
|
||||||
rules: {},
|
rules: {},
|
||||||
mode: 'automatic',
|
mode: ProcessMode.general,
|
||||||
},
|
},
|
||||||
} as CreateDocumentReq
|
} as CreateDocumentReq
|
||||||
|
|
||||||
@ -217,7 +214,7 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
|||||||
datasetId,
|
datasetId,
|
||||||
body: params,
|
body: params,
|
||||||
})
|
})
|
||||||
mutate()
|
invalidDocumentList()
|
||||||
setTimerCanRun(true)
|
setTimerCanRun(true)
|
||||||
// mutateDatasetIndexingStatus(undefined, { revalidate: true })
|
// mutateDatasetIndexingStatus(undefined, { revalidate: true })
|
||||||
setNotionPageSelectorModalVisible(false)
|
setNotionPageSelectorModalVisible(false)
|
||||||
@ -272,7 +269,7 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{(isLoading && !isMuting)
|
{isListLoading
|
||||||
? <Loading type='app' />
|
? <Loading type='app' />
|
||||||
: total > 0
|
: total > 0
|
||||||
? <List
|
? <List
|
||||||
|
@ -500,121 +500,123 @@ const DocumentList: FC<IDocumentListProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='relative w-full h-full overflow-x-auto'>
|
<div className='flex flex-col relative w-full h-full'>
|
||||||
<table className={`min-w-[700px] max-w-full w-full border-collapse border-0 text-sm mt-3 ${s.documentTable}`}>
|
<div className='grow overflow-x-auto'>
|
||||||
<thead className="h-8 leading-8 border-b border-divider-subtle text-text-tertiary font-medium text-xs uppercase">
|
<table className={`min-w-[700px] max-w-full w-full border-collapse border-0 text-sm mt-3 ${s.documentTable}`}>
|
||||||
<tr>
|
<thead className="h-8 leading-8 border-b border-divider-subtle text-text-tertiary font-medium text-xs uppercase">
|
||||||
<td className='w-12'>
|
<tr>
|
||||||
<div className='flex items-center' onClick={e => e.stopPropagation()}>
|
<td className='w-12'>
|
||||||
<Checkbox
|
|
||||||
className='shrink-0 mr-2'
|
|
||||||
checked={isAllSelected}
|
|
||||||
mixed={!isAllSelected && isSomeSelected}
|
|
||||||
onCheck={onSelectedAll}
|
|
||||||
/>
|
|
||||||
#
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div className='flex'>
|
|
||||||
{t('datasetDocuments.list.table.header.fileName')}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td className='w-[130px]'>{t('datasetDocuments.list.table.header.chunkingMode')}</td>
|
|
||||||
<td className='w-24'>{t('datasetDocuments.list.table.header.words')}</td>
|
|
||||||
<td className='w-44'>{t('datasetDocuments.list.table.header.hitCount')}</td>
|
|
||||||
<td className='w-44'>
|
|
||||||
<div className='flex items-center' onClick={onClickSort}>
|
|
||||||
{t('datasetDocuments.list.table.header.uploadTime')}
|
|
||||||
<ArrowDownIcon className={cn('ml-0.5 h-3 w-3 stroke-current stroke-2 cursor-pointer', enableSort ? 'text-text-tertiary' : 'text-text-disabled')} />
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td className='w-40'>{t('datasetDocuments.list.table.header.status')}</td>
|
|
||||||
<td className='w-20'>{t('datasetDocuments.list.table.header.action')}</td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody className="text-text-secondary">
|
|
||||||
{localDocs.map((doc, index) => {
|
|
||||||
const isFile = doc.data_source_type === DataSourceType.FILE
|
|
||||||
const fileType = isFile ? doc.data_source_detail_dict?.upload_file?.extension : ''
|
|
||||||
return <tr
|
|
||||||
key={doc.id}
|
|
||||||
className={'border-b border-divider-subtle h-8 hover:bg-background-default-hover cursor-pointer'}
|
|
||||||
onClick={() => {
|
|
||||||
router.push(`/datasets/${datasetId}/documents/${doc.id}`)
|
|
||||||
}}>
|
|
||||||
<td className='text-left align-middle text-text-tertiary text-xs'>
|
|
||||||
<div className='flex items-center' onClick={e => e.stopPropagation()}>
|
<div className='flex items-center' onClick={e => e.stopPropagation()}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
className='shrink-0 mr-2'
|
className='shrink-0 mr-2'
|
||||||
checked={selectedIds.includes(doc.id)}
|
checked={isAllSelected}
|
||||||
onCheck={() => {
|
mixed={!isAllSelected && isSomeSelected}
|
||||||
onSelectedIdChange(
|
onCheck={onSelectedAll}
|
||||||
selectedIds.includes(doc.id)
|
|
||||||
? selectedIds.filter(id => id !== doc.id)
|
|
||||||
: [...selectedIds, doc.id],
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
{/* {doc.position} */}
|
#
|
||||||
{index + 1}
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div className={'group flex items-center mr-6 hover:mr-0 max-w-[460px]'}>
|
<div className='flex'>
|
||||||
<div className='shrink-0'>
|
{t('datasetDocuments.list.table.header.fileName')}
|
||||||
{doc?.data_source_type === DataSourceType.NOTION && <NotionIcon className='inline-flex -mt-[3px] mr-1.5 align-middle' type='page' src={doc.data_source_info.notion_page_icon} />}
|
|
||||||
{doc?.data_source_type === DataSourceType.FILE && <FileTypeIcon type={extensionToFileType(doc?.data_source_info?.upload_file?.extension ?? fileType)} className='mr-1.5' />}
|
|
||||||
{doc?.data_source_type === DataSourceType.WEB && <Globe01 className='inline-flex -mt-[3px] mr-1.5 align-middle' />}
|
|
||||||
</div>
|
|
||||||
<span className='text-sm truncate grow-1'>{doc.name}</span>
|
|
||||||
<div className='group-hover:flex group-hover:ml-auto hidden shrink-0'>
|
|
||||||
<Tooltip
|
|
||||||
popupContent={t('datasetDocuments.list.table.rename')}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className='p-1 rounded-md cursor-pointer hover:bg-state-base-hover'
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation()
|
|
||||||
handleShowRenameModal(doc)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Edit03 className='w-4 h-4 text-text-tertiary' />
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td className='w-[130px]'>{t('datasetDocuments.list.table.header.chunkingMode')}</td>
|
||||||
<ChunkingModeLabel
|
<td className='w-24'>{t('datasetDocuments.list.table.header.words')}</td>
|
||||||
isGeneralMode={isGeneralMode}
|
<td className='w-44'>{t('datasetDocuments.list.table.header.hitCount')}</td>
|
||||||
isQAMode={isQAMode}
|
<td className='w-44'>
|
||||||
/>
|
<div className='flex items-center' onClick={onClickSort}>
|
||||||
</td>
|
{t('datasetDocuments.list.table.header.uploadTime')}
|
||||||
<td>{renderCount(doc.word_count)}</td>
|
<ArrowDownIcon className={cn('ml-0.5 h-3 w-3 stroke-current stroke-2 cursor-pointer', enableSort ? 'text-text-tertiary' : 'text-text-disabled')} />
|
||||||
<td>{renderCount(doc.hit_count)}</td>
|
</div>
|
||||||
<td className='text-text-secondary text-[13px]'>
|
|
||||||
{formatTime(doc.created_at, t('datasetHitTesting.dateTimeFormat') as string)}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{
|
|
||||||
(['indexing', 'splitting', 'parsing', 'cleaning'].includes(doc.indexing_status) && doc?.data_source_type === DataSourceType.NOTION)
|
|
||||||
? <ProgressBar percent={doc.percent || 0} />
|
|
||||||
: <StatusItem status={doc.display_status} />
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<OperationAction
|
|
||||||
embeddingAvailable={embeddingAvailable}
|
|
||||||
datasetId={datasetId}
|
|
||||||
detail={pick(doc, ['name', 'enabled', 'archived', 'id', 'data_source_type', 'doc_form'])}
|
|
||||||
onUpdate={onUpdate}
|
|
||||||
/>
|
|
||||||
</td>
|
</td>
|
||||||
|
<td className='w-40'>{t('datasetDocuments.list.table.header.status')}</td>
|
||||||
|
<td className='w-20'>{t('datasetDocuments.list.table.header.action')}</td>
|
||||||
</tr>
|
</tr>
|
||||||
})}
|
</thead>
|
||||||
</tbody>
|
<tbody className="text-text-secondary">
|
||||||
</table>
|
{localDocs.map((doc, index) => {
|
||||||
|
const isFile = doc.data_source_type === DataSourceType.FILE
|
||||||
|
const fileType = isFile ? doc.data_source_detail_dict?.upload_file?.extension : ''
|
||||||
|
return <tr
|
||||||
|
key={doc.id}
|
||||||
|
className={'border-b border-divider-subtle h-8 hover:bg-background-default-hover cursor-pointer'}
|
||||||
|
onClick={() => {
|
||||||
|
router.push(`/datasets/${datasetId}/documents/${doc.id}`)
|
||||||
|
}}>
|
||||||
|
<td className='text-left align-middle text-text-tertiary text-xs'>
|
||||||
|
<div className='flex items-center' onClick={e => e.stopPropagation()}>
|
||||||
|
<Checkbox
|
||||||
|
className='shrink-0 mr-2'
|
||||||
|
checked={selectedIds.includes(doc.id)}
|
||||||
|
onCheck={() => {
|
||||||
|
onSelectedIdChange(
|
||||||
|
selectedIds.includes(doc.id)
|
||||||
|
? selectedIds.filter(id => id !== doc.id)
|
||||||
|
: [...selectedIds, doc.id],
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* {doc.position} */}
|
||||||
|
{index + 1}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div className={'group flex items-center mr-6 hover:mr-0 max-w-[460px]'}>
|
||||||
|
<div className='shrink-0'>
|
||||||
|
{doc?.data_source_type === DataSourceType.NOTION && <NotionIcon className='inline-flex mt-[-3px] mr-1.5 align-middle' type='page' src={doc.data_source_info.notion_page_icon} />}
|
||||||
|
{doc?.data_source_type === DataSourceType.FILE && <FileTypeIcon type={extensionToFileType(doc?.data_source_info?.upload_file?.extension ?? fileType)} className='mr-1.5' />}
|
||||||
|
{doc?.data_source_type === DataSourceType.WEB && <Globe01 className='inline-flex mt-[-3px] mr-1.5 align-middle' />}
|
||||||
|
</div>
|
||||||
|
<span className='text-sm truncate grow-1'>{doc.name}</span>
|
||||||
|
<div className='group-hover:flex group-hover:ml-auto hidden shrink-0'>
|
||||||
|
<Tooltip
|
||||||
|
popupContent={t('datasetDocuments.list.table.rename')}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className='p-1 rounded-md cursor-pointer hover:bg-state-base-hover'
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
handleShowRenameModal(doc)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Edit03 className='w-4 h-4 text-text-tertiary' />
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ChunkingModeLabel
|
||||||
|
isGeneralMode={isGeneralMode}
|
||||||
|
isQAMode={isQAMode}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td>{renderCount(doc.word_count)}</td>
|
||||||
|
<td>{renderCount(doc.hit_count)}</td>
|
||||||
|
<td className='text-text-secondary text-[13px]'>
|
||||||
|
{formatTime(doc.created_at, t('datasetHitTesting.dateTimeFormat') as string)}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{
|
||||||
|
(['indexing', 'splitting', 'parsing', 'cleaning'].includes(doc.indexing_status) && doc?.data_source_type === DataSourceType.NOTION)
|
||||||
|
? <ProgressBar percent={doc.percent || 0} />
|
||||||
|
: <StatusItem status={doc.display_status} />
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<OperationAction
|
||||||
|
embeddingAvailable={embeddingAvailable}
|
||||||
|
datasetId={datasetId}
|
||||||
|
detail={pick(doc, ['name', 'enabled', 'archived', 'id', 'data_source_type', 'doc_form'])}
|
||||||
|
onUpdate={onUpdate}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
{(selectedIds.length > 0) && (
|
{(selectedIds.length > 0) && (
|
||||||
<BatchAction
|
<BatchAction
|
||||||
className='absolute left-0 bottom-16 z-20'
|
className='absolute left-0 bottom-16 z-20'
|
||||||
@ -629,10 +631,10 @@ const DocumentList: FC<IDocumentListProps> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{/* Show Pagination only if the total is more than the limit */}
|
{/* Show Pagination only if the total is more than the limit */}
|
||||||
{pagination.total && pagination.total > (pagination.limit || 10) && (
|
{pagination.total && (
|
||||||
<Pagination
|
<Pagination
|
||||||
{...pagination}
|
{...pagination}
|
||||||
className='absolute bottom-0 left-0 w-full px-0 pb-0'
|
className='shrink-0 w-full px-0 pb-0'
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import type {
|
|||||||
CreateDocumentReq,
|
CreateDocumentReq,
|
||||||
DataSet,
|
DataSet,
|
||||||
DataSetListResponse,
|
DataSetListResponse,
|
||||||
DocumentListResponse,
|
|
||||||
ErrorDocsResponse,
|
ErrorDocsResponse,
|
||||||
ExternalAPIDeleteResponse,
|
ExternalAPIDeleteResponse,
|
||||||
ExternalAPIItem,
|
ExternalAPIItem,
|
||||||
@ -122,10 +121,6 @@ export const fetchProcessRule: Fetcher<ProcessRuleResponse, { params: { document
|
|||||||
return get<ProcessRuleResponse>('/datasets/process-rule', { params: { document_id: documentId } })
|
return get<ProcessRuleResponse>('/datasets/process-rule', { params: { document_id: documentId } })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchDocuments: Fetcher<DocumentListResponse, { datasetId: string; params: { keyword: string; page: number; limit: number; sort?: SortType } }> = ({ datasetId, params }) => {
|
|
||||||
return get<DocumentListResponse>(`/datasets/${datasetId}/documents`, { params })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createFirstDocument: Fetcher<createDocumentResponse, { body: CreateDocumentReq }> = ({ body }) => {
|
export const createFirstDocument: Fetcher<createDocumentResponse, { body: CreateDocumentReq }> = ({ body }) => {
|
||||||
return post<createDocumentResponse>('/datasets/init', { body })
|
return post<createDocumentResponse>('/datasets/init', { body })
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@ import {
|
|||||||
} from '@tanstack/react-query'
|
} from '@tanstack/react-query'
|
||||||
import { del, get, patch } from '../base'
|
import { del, get, patch } from '../base'
|
||||||
import { useInvalid } from '../use-base'
|
import { useInvalid } from '../use-base'
|
||||||
import type { MetadataType } from '../datasets'
|
import type { MetadataType, SortType } from '../datasets'
|
||||||
import type { DocumentDetailResponse, SimpleDocumentDetail, UpdateDocumentBatchParams } from '@/models/datasets'
|
import type { DocumentDetailResponse, DocumentListResponse, UpdateDocumentBatchParams } from '@/models/datasets'
|
||||||
import { DocumentActionType } from '@/models/datasets'
|
import { DocumentActionType } from '@/models/datasets'
|
||||||
import type { CommonResponse } from '@/models/common'
|
import type { CommonResponse } from '@/models/common'
|
||||||
|
|
||||||
@ -18,19 +18,23 @@ export const useDocumentList = (payload: {
|
|||||||
keyword: string
|
keyword: string
|
||||||
page: number
|
page: number
|
||||||
limit: number
|
limit: number
|
||||||
}
|
sort?: SortType
|
||||||
|
},
|
||||||
|
refetchInterval?: number | false
|
||||||
}) => {
|
}) => {
|
||||||
const { query, datasetId } = payload
|
const { query, datasetId, refetchInterval } = payload
|
||||||
return useQuery<{ data: SimpleDocumentDetail[] }>({
|
const { keyword, page, limit, sort } = query
|
||||||
queryKey: [...useDocumentListKey, datasetId, query],
|
return useQuery<DocumentListResponse>({
|
||||||
queryFn: () => get<{ data: SimpleDocumentDetail[] }>(`/datasets/${datasetId}/documents`, {
|
queryKey: [...useDocumentListKey, datasetId, keyword, page, limit, sort],
|
||||||
|
queryFn: () => get<DocumentListResponse>(`/datasets/${datasetId}/documents`, {
|
||||||
params: query,
|
params: query,
|
||||||
}),
|
}),
|
||||||
|
refetchInterval,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useInvalidDocumentList = () => {
|
export const useInvalidDocumentList = (datasetId?: string) => {
|
||||||
return useInvalid(useDocumentListKey)
|
return useInvalid(datasetId ? [...useDocumentListKey, datasetId] : useDocumentListKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
const useAutoDisabledDocumentKey = [NAME_SPACE, 'autoDisabledDocument']
|
const useAutoDisabledDocumentKey = [NAME_SPACE, 'autoDisabledDocument']
|
||||||
|
Loading…
x
Reference in New Issue
Block a user