mirror of
https://github.com/langgenius/dify.git
synced 2025-12-27 10:02:25 +00:00
refactor: enhance document preview functionality and refactor form handling
This commit is contained in:
parent
5ac1e3584d
commit
29d2f2339b
@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
import { useCallback, useMemo, useRef, useState } from 'react'
|
||||
import DataSourceOptions from './data-source-options'
|
||||
import type { CrawlResultItem, CustomFile as File, FileIndexingEstimateResponse, FileItem } from '@/models/datasets'
|
||||
import type { CrawlResultItem, DocumentItem, CustomFile as File, FileIndexingEstimateResponse, FileItem } from '@/models/datasets'
|
||||
import LocalFile from '@/app/components/rag-pipeline/components/panel/test-run/data-source/local-file'
|
||||
import produce from 'immer'
|
||||
import { useProviderContextSelector } from '@/context/provider-context'
|
||||
@ -48,6 +48,9 @@ const TestRunPanel = () => {
|
||||
|
||||
const isPreview = useRef(false)
|
||||
const formRef = useRef<any>(null)
|
||||
const previewFile = useRef<DocumentItem>(fileList[0].file as DocumentItem)
|
||||
const previewNotionPage = useRef<NotionPage>(notionPages[0])
|
||||
const previewWebsitePage = useRef<CrawlResultItem>(websitePages[0])
|
||||
|
||||
const { data: pipelineInfo, isFetching: isFetchingPipelineInfo } = usePublishedPipelineInfo(pipelineId || '')
|
||||
|
||||
@ -132,7 +135,7 @@ const TestRunPanel = () => {
|
||||
return
|
||||
const datasourceInfoList: Record<string, any>[] = []
|
||||
if (datasource.type === DatasourceType.localFile) {
|
||||
const { id, name, type, size, extension, mime_type } = fileList[0].file
|
||||
const { id, name, type, size, extension, mime_type } = previewFile.current as File
|
||||
const documentInfo = {
|
||||
upload_file_id: id,
|
||||
name,
|
||||
@ -144,7 +147,7 @@ const TestRunPanel = () => {
|
||||
datasourceInfoList.push(documentInfo)
|
||||
}
|
||||
if (datasource.type === DatasourceType.onlineDocument) {
|
||||
const { workspace_id, ...rest } = notionPages[0]
|
||||
const { workspace_id, ...rest } = previewNotionPage.current
|
||||
const documentInfo = {
|
||||
workspace_id,
|
||||
page: rest,
|
||||
@ -154,7 +157,7 @@ const TestRunPanel = () => {
|
||||
if (datasource.type === DatasourceType.websiteCrawl) {
|
||||
const documentInfo = {
|
||||
job_id: websiteCrawlJobId,
|
||||
result: websitePages[0],
|
||||
result: previewWebsitePage.current,
|
||||
}
|
||||
datasourceInfoList.push(documentInfo)
|
||||
}
|
||||
@ -167,10 +170,10 @@ const TestRunPanel = () => {
|
||||
is_preview: true,
|
||||
}, {
|
||||
onSuccess: (res) => {
|
||||
setEstimateData(res as FileIndexingEstimateResponse)
|
||||
setEstimateData(res.data.outputs as FileIndexingEstimateResponse)
|
||||
},
|
||||
})
|
||||
}, [datasource, fileList, notionPages, pipelineId, runPublishedPipeline, websiteCrawlJobId, websitePages])
|
||||
}, [datasource, pipelineId, runPublishedPipeline, websiteCrawlJobId])
|
||||
|
||||
const handleProcess = useCallback(async (data: Record<string, any>) => {
|
||||
if (!datasource)
|
||||
@ -231,14 +234,25 @@ const TestRunPanel = () => {
|
||||
formRef.current?.submit()
|
||||
}, [])
|
||||
|
||||
const onClickReset = useCallback(() => {
|
||||
formRef.current?.reset()
|
||||
}, [])
|
||||
|
||||
const handleSubmit = useCallback((data: Record<string, any>) => {
|
||||
isPreview.current ? handlePreviewChunks(data) : handleProcess(data)
|
||||
}, [handlePreviewChunks, handleProcess])
|
||||
|
||||
const handlePreviewFileChange = useCallback((file: DocumentItem) => {
|
||||
previewFile.current = file
|
||||
onClickPreview()
|
||||
}, [onClickPreview])
|
||||
|
||||
const handlePreviewNotionPageChange = useCallback((page: NotionPage) => {
|
||||
previewNotionPage.current = page
|
||||
onClickPreview()
|
||||
}, [onClickPreview])
|
||||
|
||||
const handlePreviewWebsiteChange = useCallback((website: CrawlResultItem) => {
|
||||
previewWebsitePage.current = website
|
||||
onClickPreview()
|
||||
}, [onClickPreview])
|
||||
|
||||
if (isFetchingPipelineInfo) {
|
||||
return (
|
||||
<Loading type='app' />
|
||||
@ -312,7 +326,6 @@ const TestRunPanel = () => {
|
||||
onProcess={onClickProcess}
|
||||
onPreview={onClickPreview}
|
||||
onSubmit={handleSubmit}
|
||||
onReset={onClickReset}
|
||||
onBack={handleBackStep}
|
||||
/>
|
||||
)
|
||||
@ -353,6 +366,9 @@ const TestRunPanel = () => {
|
||||
isPending={isPending}
|
||||
estimateData={estimateData}
|
||||
onPreview={onClickPreview}
|
||||
handlePreviewFileChange={handlePreviewFileChange}
|
||||
handlePreviewNotionPageChange={handlePreviewNotionPageChange}
|
||||
handlePreviewWebsitePageChange={handlePreviewWebsiteChange}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -26,6 +26,9 @@ type ChunkPreviewProps = {
|
||||
isPending: boolean
|
||||
estimateData: FileIndexingEstimateResponse | undefined
|
||||
onPreview: () => void
|
||||
handlePreviewFileChange: (file: DocumentItem) => void
|
||||
handlePreviewNotionPageChange: (page: NotionPage) => void
|
||||
handlePreviewWebsitePageChange: (page: CrawlResultItem) => void
|
||||
}
|
||||
|
||||
const ChunkPreview = ({
|
||||
@ -37,6 +40,9 @@ const ChunkPreview = ({
|
||||
isPending,
|
||||
estimateData,
|
||||
onPreview,
|
||||
handlePreviewFileChange,
|
||||
handlePreviewNotionPageChange,
|
||||
handlePreviewWebsitePageChange,
|
||||
}: ChunkPreviewProps) => {
|
||||
const { t } = useTranslation()
|
||||
const currentDocForm = useDatasetDetailContextWithSelector(s => s.dataset?.doc_form)
|
||||
@ -58,6 +64,7 @@ const ChunkPreview = ({
|
||||
files={files as Array<Required<CustomFile>>}
|
||||
onChange={(selected) => {
|
||||
setPreviewFile(selected)
|
||||
handlePreviewFileChange(selected)
|
||||
}}
|
||||
value={previewFile}
|
||||
/>
|
||||
@ -74,6 +81,7 @@ const ChunkPreview = ({
|
||||
onChange={(selected) => {
|
||||
const selectedPage = notionPages.find(page => page.page_id === selected.id)
|
||||
setPreviewNotionPage(selectedPage!)
|
||||
handlePreviewNotionPageChange(selectedPage!)
|
||||
}}
|
||||
value={{
|
||||
id: previewNotionPage?.page_id || '',
|
||||
@ -94,6 +102,7 @@ const ChunkPreview = ({
|
||||
onChange={(selected) => {
|
||||
const selectedPage = websitePages.find(page => page.source_url === selected.id)
|
||||
setPreviewWebsitePage(selectedPage!)
|
||||
handlePreviewWebsitePageChange(selectedPage!)
|
||||
}}
|
||||
value={
|
||||
{
|
||||
@ -113,7 +122,7 @@ const ChunkPreview = ({
|
||||
}
|
||||
</div>
|
||||
</PreviewHeader>}
|
||||
className='relative flex h-full w-1/2 shrink-0 p-4 pr-0'
|
||||
className='relative flex h-full w-full shrink-0'
|
||||
mainClassName='space-y-6'
|
||||
>
|
||||
{currentDocForm === ChunkingMode.qa && estimateData?.qa_preview && (
|
||||
@ -169,7 +178,7 @@ const ChunkPreview = ({
|
||||
)
|
||||
})
|
||||
)}
|
||||
{!isIdle && (
|
||||
{isIdle && (
|
||||
<div className='flex h-full w-full items-center justify-center'>
|
||||
<div className='flex flex-col items-center justify-center gap-3 pb-4'>
|
||||
<RiSearchEyeLine className='size-10 text-text-empty-state-icon' />
|
||||
|
||||
@ -2,22 +2,25 @@ import { useAppForm } from '@/app/components/base/form'
|
||||
import BaseField from '@/app/components/base/form/form-scenarios/base/field'
|
||||
import type { BaseConfiguration } from '@/app/components/base/form/form-scenarios/base/types'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { useImperativeHandle } from 'react'
|
||||
import { useCallback, useImperativeHandle } from 'react'
|
||||
import type { ZodSchema } from 'zod'
|
||||
import Header from './header'
|
||||
|
||||
type OptionsProps = {
|
||||
initialData: Record<string, any>
|
||||
configurations: BaseConfiguration[]
|
||||
schema: ZodSchema
|
||||
onSubmit: (data: Record<string, any>) => void
|
||||
onPreview: () => void
|
||||
ref: React.RefObject<any>
|
||||
}
|
||||
|
||||
const Options = ({
|
||||
const Form = ({
|
||||
initialData,
|
||||
configurations,
|
||||
schema,
|
||||
onSubmit,
|
||||
onPreview,
|
||||
ref,
|
||||
}: OptionsProps) => {
|
||||
const form = useAppForm({
|
||||
@ -48,24 +51,32 @@ const Options = ({
|
||||
submit: () => {
|
||||
form.handleSubmit()
|
||||
},
|
||||
reset: () => {
|
||||
form.reset()
|
||||
},
|
||||
isDirty: () => {
|
||||
return form.state.isDirty
|
||||
},
|
||||
}
|
||||
}, [form])
|
||||
|
||||
const handleReset = useCallback(() => {
|
||||
form.reset()
|
||||
}, [form])
|
||||
|
||||
return (
|
||||
<form
|
||||
className='w-full'
|
||||
className='flex w-full flex-col rounded-lg border border-components-panel-border bg-components-panel-bg'
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
form.handleSubmit()
|
||||
}}
|
||||
>
|
||||
<form.Subscribe
|
||||
selector={state => state.isDirty}
|
||||
children={isDirty => (
|
||||
<Header
|
||||
onReset={handleReset}
|
||||
resetDisabled={!isDirty}
|
||||
onPreview={onPreview}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<div className='flex flex-col gap-3 border-t border-divider-subtle px-4 py-3'>
|
||||
{configurations.map((config, index) => {
|
||||
const FieldComponent = BaseField({
|
||||
@ -79,4 +90,4 @@ const Options = ({
|
||||
)
|
||||
}
|
||||
|
||||
export default Options
|
||||
export default Form
|
||||
@ -5,13 +5,13 @@ import { RiSearchEyeLine } from '@remixicon/react'
|
||||
|
||||
type HeaderProps = {
|
||||
onReset: () => void
|
||||
disableReset?: boolean
|
||||
resetDisabled: boolean
|
||||
onPreview?: () => void
|
||||
}
|
||||
|
||||
const Header = ({
|
||||
onReset,
|
||||
disableReset = true,
|
||||
resetDisabled,
|
||||
onPreview,
|
||||
}: HeaderProps) => {
|
||||
const { t } = useTranslation()
|
||||
@ -21,7 +21,7 @@ const Header = ({
|
||||
<div className='system-sm-semibold-uppercase grow text-text-secondary'>
|
||||
{t('datasetPipeline.addDocuments.stepTwo.chunkSettings')}
|
||||
</div>
|
||||
<Button variant='ghost' disabled={disableReset} onClick={onReset}>
|
||||
<Button variant='ghost' disabled={resetDisabled} onClick={onReset}>
|
||||
{t('common.operation.reset')}
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
@ -1,15 +1,13 @@
|
||||
import { generateZodSchema } from '@/app/components/base/form/form-scenarios/base/utils'
|
||||
import { useConfigurations } from './hooks'
|
||||
import Options from './options'
|
||||
import Form from './form'
|
||||
import Actions from './actions'
|
||||
import Header from './header'
|
||||
|
||||
type ProcessDocumentsProps = {
|
||||
dataSourceNodeId: string
|
||||
ref: React.RefObject<any>
|
||||
onProcess: () => void
|
||||
onPreview: () => void
|
||||
onReset: () => void
|
||||
onSubmit: (data: Record<string, any>) => void
|
||||
onBack: () => void
|
||||
}
|
||||
@ -19,7 +17,6 @@ const ProcessDocuments = ({
|
||||
onProcess,
|
||||
onPreview,
|
||||
onSubmit,
|
||||
onReset,
|
||||
onBack,
|
||||
ref,
|
||||
}: ProcessDocumentsProps) => {
|
||||
@ -28,20 +25,14 @@ const ProcessDocuments = ({
|
||||
|
||||
return (
|
||||
<div className='flex flex-col gap-y-4 pt-4'>
|
||||
<div className='flex flex-col rounded-lg border border-components-panel-border bg-components-panel-bg'>
|
||||
<Header
|
||||
onReset={onReset}
|
||||
disableReset={!ref.current?.isDirty()}
|
||||
onPreview={onPreview}
|
||||
/>
|
||||
<Options
|
||||
ref={ref}
|
||||
initialData={initialData}
|
||||
configurations={configurations}
|
||||
schema={schema}
|
||||
onSubmit={onSubmit}
|
||||
/>
|
||||
</div>
|
||||
<Form
|
||||
ref={ref}
|
||||
initialData={initialData}
|
||||
configurations={configurations}
|
||||
schema={schema}
|
||||
onSubmit={onSubmit}
|
||||
onPreview={onPreview}
|
||||
/>
|
||||
<Actions onBack={onBack} onProcess={onProcess} />
|
||||
</div>
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user