mirror of
https://github.com/langgenius/dify.git
synced 2026-07-31 17:29:37 +08:00
154 lines
5.0 KiB
TypeScript
154 lines
5.0 KiB
TypeScript
'use client'
|
|
|
|
import type {
|
|
LogicalDocument,
|
|
LogicalDocumentRevision,
|
|
} from '@dify/contracts/knowledge-fs/types.gen'
|
|
import { Button } from '@langgenius/dify-ui/button'
|
|
import { useInfiniteQuery } from '@tanstack/react-query'
|
|
import { useMemo, useState } from 'react'
|
|
import { useTranslation } from 'react-i18next'
|
|
import Loading from '@/app/components/base/loading'
|
|
import { DocumentChunkDetail } from './document-chunk-detail'
|
|
import { DocumentChunkTreePanel } from './document-chunk-tree'
|
|
import { buildDocumentChunkTree } from './document-detail-model'
|
|
import { documentChunksQueryOptions } from './document-detail-queries'
|
|
|
|
export function DocumentRevisionContent({
|
|
document,
|
|
documentId,
|
|
effectiveRevision,
|
|
knowledgeSpaceId,
|
|
locale,
|
|
revision,
|
|
revisionHistoryError,
|
|
revisionHistoryPending,
|
|
retryRevisionHistory,
|
|
}: {
|
|
document: LogicalDocument
|
|
documentId: string
|
|
effectiveRevision?: number
|
|
knowledgeSpaceId: string
|
|
locale: string
|
|
revision?: Exclude<LogicalDocumentRevision, null>
|
|
revisionHistoryError: boolean
|
|
revisionHistoryPending: boolean
|
|
retryRevisionHistory: () => void
|
|
}) {
|
|
const { t } = useTranslation('dataset')
|
|
const { t: tCommon } = useTranslation('common')
|
|
|
|
if (effectiveRevision === undefined && revisionHistoryPending)
|
|
return (
|
|
<div className="flex min-h-80 items-center justify-center">
|
|
<Loading />
|
|
</div>
|
|
)
|
|
|
|
if (effectiveRevision === undefined && revisionHistoryError)
|
|
return (
|
|
<div className="flex min-h-80 flex-col items-center justify-center px-6 text-center">
|
|
<span aria-hidden className="i-ri-error-warning-line size-8 text-text-destructive" />
|
|
<h2 className="mt-3 title-2xl-semi-bold text-text-primary">
|
|
{t(($) => $['newKnowledge.documentLoadErrorTitle'])}
|
|
</h2>
|
|
<p className="mt-2 max-w-lg body-sm-regular text-text-tertiary">
|
|
{t(($) => $['newKnowledge.documentLoadErrorDescription'])}
|
|
</p>
|
|
<Button className="mt-4" onClick={retryRevisionHistory}>
|
|
{tCommon(($) => $['operation.retry'])}
|
|
</Button>
|
|
</div>
|
|
)
|
|
|
|
if (effectiveRevision === undefined)
|
|
return (
|
|
<div className="flex min-h-80 flex-col items-center justify-center text-center">
|
|
<span aria-hidden className="i-ri-file-warning-line size-8 text-text-tertiary" />
|
|
<h2 className="mt-3 title-xl-semi-bold text-text-primary">
|
|
{t(($) => $['newKnowledge.documentRevisionMissingTitle'])}
|
|
</h2>
|
|
<p className="mt-2 max-w-lg body-sm-regular text-text-tertiary">
|
|
{t(($) => $['newKnowledge.documentRevisionMissingDescription'])}
|
|
</p>
|
|
</div>
|
|
)
|
|
|
|
return (
|
|
<LoadedDocumentRevisionContent
|
|
document={document}
|
|
documentId={documentId}
|
|
effectiveRevision={effectiveRevision}
|
|
knowledgeSpaceId={knowledgeSpaceId}
|
|
locale={locale}
|
|
revision={revision}
|
|
/>
|
|
)
|
|
}
|
|
|
|
function LoadedDocumentRevisionContent({
|
|
document,
|
|
documentId,
|
|
effectiveRevision,
|
|
knowledgeSpaceId,
|
|
locale,
|
|
revision,
|
|
}: {
|
|
document: LogicalDocument
|
|
documentId: string
|
|
effectiveRevision: number
|
|
knowledgeSpaceId: string
|
|
locale: string
|
|
revision?: Exclude<LogicalDocumentRevision, null>
|
|
}) {
|
|
const [selectedChunkId, setSelectedChunkId] = useState<string>()
|
|
const chunksQueryOptions = useMemo(
|
|
() => documentChunksQueryOptions({ documentId, effectiveRevision, knowledgeSpaceId }),
|
|
[documentId, effectiveRevision, knowledgeSpaceId],
|
|
)
|
|
const chunksQuery = useInfiniteQuery(chunksQueryOptions)
|
|
const chunks = useMemo(
|
|
() =>
|
|
[...(chunksQuery.data?.pages.flatMap((page) => page.items) ?? [])].sort(
|
|
(left, right) => left.ordinal - right.ordinal || left.id.localeCompare(right.id),
|
|
),
|
|
[chunksQuery.data],
|
|
)
|
|
const tree = useMemo(() => buildDocumentChunkTree(chunks), [chunks])
|
|
const selectedChunk =
|
|
(selectedChunkId ? tree.byId.get(selectedChunkId)?.chunk : undefined) ?? tree.roots[0]?.chunk
|
|
|
|
return (
|
|
<div className="mt-7 grid min-h-0 flex-1 gap-4 xl:grid-cols-[14rem_minmax(0,1fr)_20rem] xl:gap-0">
|
|
<DocumentChunkTreePanel
|
|
chunkCount={chunks.length}
|
|
error={Boolean(chunksQuery.error)}
|
|
fetchNextPage={chunksQuery.fetchNextPage}
|
|
hasNextPage={chunksQuery.hasNextPage}
|
|
isFetchNextPageError={chunksQuery.isFetchNextPageError}
|
|
isFetchingNextPage={chunksQuery.isFetchingNextPage}
|
|
isPending={chunksQuery.isPending}
|
|
onRetry={() => void chunksQuery.refetch()}
|
|
onSelectChunk={setSelectedChunkId}
|
|
selectedChunkId={selectedChunk?.id}
|
|
tree={tree}
|
|
/>
|
|
|
|
<DocumentChunkDetail
|
|
chunks={chunks}
|
|
chunksComplete={
|
|
Boolean(chunksQuery.data) &&
|
|
!chunksQuery.error &&
|
|
!chunksQuery.hasNextPage &&
|
|
!chunksQuery.isFetchingNextPage &&
|
|
!chunksQuery.isFetchNextPageError
|
|
}
|
|
document={document}
|
|
locale={locale}
|
|
revision={revision}
|
|
selectedChunkId={selectedChunk?.id}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|