feat: parent child retrieval (#12106)
Signed-off-by: -LAN- <laipz8200@outlook.com> Co-authored-by: -LAN- <laipz8200@outlook.com>
This commit is contained in:
@@ -1,18 +1,19 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import useSWR from 'swr'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useDebounce, useDebounceFn } from 'ahooks'
|
||||
import { groupBy, omit } from 'lodash-es'
|
||||
import { PlusIcon } from '@heroicons/react/24/solid'
|
||||
import { RiExternalLinkLine } from '@remixicon/react'
|
||||
import AutoDisabledDocument from '../common/document-status-with-action/auto-disabled-document'
|
||||
import List from './list'
|
||||
import s from './style.module.css'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Pagination from '@/app/components/base/pagination'
|
||||
import { get } from '@/service/base'
|
||||
import { createDocument, fetchDocuments } from '@/service/datasets'
|
||||
import { useDatasetDetailContext } from '@/context/dataset-detail'
|
||||
@@ -20,10 +21,9 @@ import { NotionPageSelectorModal } from '@/app/components/base/notion-page-selec
|
||||
import type { NotionPage } from '@/models/common'
|
||||
import type { CreateDocumentReq } from '@/models/datasets'
|
||||
import { DataSourceType } from '@/models/datasets'
|
||||
import RetryButton from '@/app/components/base/retry-button'
|
||||
// Custom page count is not currently supported.
|
||||
const limit = 15
|
||||
|
||||
import IndexFailed from '@/app/components/datasets/common/document-status-with-action/index-failed'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import cn from '@/utils/classnames'
|
||||
const FolderPlusIcon = ({ className }: React.SVGProps<SVGElement>) => {
|
||||
return <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
|
||||
<path d="M10.8332 5.83333L9.90355 3.9741C9.63601 3.439 9.50222 3.17144 9.30265 2.97597C9.12615 2.80311 8.91344 2.67164 8.6799 2.59109C8.41581 2.5 8.11668 2.5 7.51841 2.5H4.33317C3.39975 2.5 2.93304 2.5 2.57652 2.68166C2.26292 2.84144 2.00795 3.09641 1.84816 3.41002C1.6665 3.76654 1.6665 4.23325 1.6665 5.16667V5.83333M1.6665 5.83333H14.3332C15.7333 5.83333 16.4334 5.83333 16.9681 6.10582C17.4386 6.3455 17.821 6.72795 18.0607 7.19836C18.3332 7.73314 18.3332 8.4332 18.3332 9.83333V13.5C18.3332 14.9001 18.3332 15.6002 18.0607 16.135C17.821 16.6054 17.4386 16.9878 16.9681 17.2275C16.4334 17.5 15.7333 17.5 14.3332 17.5H5.6665C4.26637 17.5 3.56631 17.5 3.03153 17.2275C2.56112 16.9878 2.17867 16.6054 1.93899 16.135C1.6665 15.6002 1.6665 14.9001 1.6665 13.5V5.83333ZM9.99984 14.1667V9.16667M7.49984 11.6667H12.4998" stroke="#667085" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||
@@ -74,12 +74,16 @@ type IDocumentsProps = {
|
||||
}
|
||||
|
||||
export const fetcher = (url: string) => get(url, {}, {})
|
||||
const DEFAULT_LIMIT = 15
|
||||
|
||||
const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
||||
const { t } = useTranslation()
|
||||
const { plan } = useProviderContext()
|
||||
const isFreePlan = plan.type === 'sandbox'
|
||||
const [inputValue, setInputValue] = useState<string>('') // the input value
|
||||
const [searchValue, setSearchValue] = useState<string>('')
|
||||
const [currPage, setCurrPage] = React.useState<number>(0)
|
||||
const [limit, setLimit] = useState<number>(DEFAULT_LIMIT)
|
||||
const router = useRouter()
|
||||
const { dataset } = useDatasetDetailContext()
|
||||
const [notionPageSelectorModalVisible, setNotionPageSelectorModalVisible] = useState(false)
|
||||
@@ -93,9 +97,9 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
||||
|
||||
const query = useMemo(() => {
|
||||
return { page: currPage + 1, limit, keyword: debouncedSearchValue, fetch: isDataSourceNotion ? true : '' }
|
||||
}, [currPage, debouncedSearchValue, isDataSourceNotion])
|
||||
}, [currPage, debouncedSearchValue, isDataSourceNotion, limit])
|
||||
|
||||
const { data: documentsRes, error, mutate } = useSWR(
|
||||
const { data: documentsRes, error, mutate, isLoading: isListLoading } = useSWR(
|
||||
{
|
||||
action: 'fetchDocuments',
|
||||
datasetId,
|
||||
@@ -105,6 +109,17 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
||||
{ refreshInterval: (isDataSourceNotion && timerCanRun) ? 2500 : 0 },
|
||||
)
|
||||
|
||||
const [isMuting, setIsMuting] = useState(false)
|
||||
useEffect(() => {
|
||||
if (!isListLoading && isMuting)
|
||||
setIsMuting(false)
|
||||
}, [isListLoading, isMuting])
|
||||
|
||||
const handleUpdate = useCallback(() => {
|
||||
setIsMuting(true)
|
||||
mutate()
|
||||
}, [mutate])
|
||||
|
||||
const documentsWithProgress = useMemo(() => {
|
||||
let completedNum = 0
|
||||
let percent = 0
|
||||
@@ -146,7 +161,7 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
||||
router.push(`/datasets/${datasetId}/documents/create`)
|
||||
}
|
||||
|
||||
const isLoading = !documentsRes && !error
|
||||
const isLoading = isListLoading // !documentsRes && !error
|
||||
|
||||
const handleSaveNotionPageSelected = async (selectedPages: NotionPage[]) => {
|
||||
const workspacesMap = groupBy(selectedPages, 'workspace_id')
|
||||
@@ -195,7 +210,7 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
||||
}
|
||||
|
||||
const documentsList = isDataSourceNotion ? documentsWithProgress?.data : documentsRes?.data
|
||||
|
||||
const [selectedIds, setSelectedIds] = useState<string[]>([])
|
||||
const { run: handleSearch } = useDebounceFn(() => {
|
||||
setSearchValue(inputValue)
|
||||
}, { wait: 500 })
|
||||
@@ -208,8 +223,17 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
||||
return (
|
||||
<div className='flex flex-col h-full overflow-y-auto'>
|
||||
<div className='flex flex-col justify-center gap-1 px-6 pt-4'>
|
||||
<h1 className={s.title}>{t('datasetDocuments.list.title')}</h1>
|
||||
<p className={s.desc}>{t('datasetDocuments.list.desc')}</p>
|
||||
<h1 className='text-base font-semibold text-text-primary'>{t('datasetDocuments.list.title')}</h1>
|
||||
<div className='flex items-center text-sm font-normal text-text-tertiary space-x-0.5'>
|
||||
<span>{t('datasetDocuments.list.desc')}</span>
|
||||
<a
|
||||
className='flex items-center text-text-accent'
|
||||
target='_blank'
|
||||
href='https://docs.dify.ai/guides/knowledge-base/integrate-knowledge-within-application'>
|
||||
<span>{t('datasetDocuments.list.learnMore')}</span>
|
||||
<RiExternalLinkLine className='w-3 h-3' />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-col px-6 py-4 flex-1'>
|
||||
<div className='flex items-center justify-between flex-wrap'>
|
||||
@@ -222,27 +246,38 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
||||
onClear={() => handleInputChange('')}
|
||||
/>
|
||||
<div className='flex gap-2 justify-center items-center !h-8'>
|
||||
<RetryButton datasetId={datasetId} />
|
||||
{!isFreePlan && <AutoDisabledDocument datasetId={datasetId} />}
|
||||
<IndexFailed datasetId={datasetId} />
|
||||
{embeddingAvailable && (
|
||||
<Button variant='primary' onClick={routeToDocCreate} className='shrink-0'>
|
||||
<PlusIcon className='h-4 w-4 mr-2 stroke-current' />
|
||||
<PlusIcon className={cn('h-4 w-4 mr-2 stroke-current')} />
|
||||
{isDataSourceNotion && t('datasetDocuments.list.addPages')}
|
||||
{isDataSourceWeb && t('datasetDocuments.list.addUrl')}
|
||||
{isDataSourceFile && t('datasetDocuments.list.addFile')}
|
||||
{(!dataset?.data_source_type || isDataSourceFile) && t('datasetDocuments.list.addFile')}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{isLoading
|
||||
{(isLoading && !isMuting)
|
||||
? <Loading type='app' />
|
||||
: total > 0
|
||||
? <List embeddingAvailable={embeddingAvailable} documents={documentsList || []} datasetId={datasetId} onUpdate={mutate} />
|
||||
? <List
|
||||
embeddingAvailable={embeddingAvailable}
|
||||
documents={documentsList || []}
|
||||
datasetId={datasetId}
|
||||
onUpdate={handleUpdate}
|
||||
selectedIds={selectedIds}
|
||||
onSelectedIdChange={setSelectedIds}
|
||||
pagination={{
|
||||
total,
|
||||
limit,
|
||||
onLimitChange: setLimit,
|
||||
current: currPage,
|
||||
onChange: setCurrPage,
|
||||
}}
|
||||
/>
|
||||
: <EmptyElement canAdd={embeddingAvailable} onClick={routeToDocCreate} type={isDataSourceNotion ? 'sync' : 'upload'} />
|
||||
}
|
||||
{/* Show Pagination only if the total is more than the limit */}
|
||||
{(total && total > limit)
|
||||
? <Pagination current={currPage} onChange={setCurrPage} total={total} limit={limit} />
|
||||
: null}
|
||||
<NotionPageSelectorModal
|
||||
isShow={notionPageSelectorModalVisible}
|
||||
onClose={() => setNotionPageSelectorModalVisible(false)}
|
||||
|
Reference in New Issue
Block a user