mirror of
https://github.com/langgenius/dify.git
synced 2025-08-01 13:58:23 +00:00
202 lines
6.5 KiB
TypeScript
202 lines
6.5 KiB
TypeScript
import type { DataSourceNodeType } from '@/app/components/workflow/nodes/data-source/types'
|
|
import Header from './header'
|
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
|
import FileList from './file-list'
|
|
import type { OnlineDriveFile } from '@/models/pipeline'
|
|
import { DatasourceType, OnlineDriveFileType } from '@/models/pipeline'
|
|
import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail'
|
|
import { ssePost } from '@/service/base'
|
|
import type { DataSourceNodeCompletedResponse, DataSourceNodeErrorResponse } from '@/types/pipeline'
|
|
import Toast from '@/app/components/base/toast'
|
|
import { useDataSourceStore, useDataSourceStoreWithSelector } from '../store'
|
|
import { convertOnlineDriveData } from './utils'
|
|
import produce from 'immer'
|
|
import { useShallow } from 'zustand/react/shallow'
|
|
|
|
type OnlineDriveProps = {
|
|
nodeId: string
|
|
nodeData: DataSourceNodeType
|
|
isInPipeline?: boolean
|
|
}
|
|
|
|
const OnlineDrive = ({
|
|
nodeId,
|
|
nodeData,
|
|
isInPipeline = false,
|
|
}: OnlineDriveProps) => {
|
|
const pipelineId = useDatasetDetailContextWithSelector(s => s.dataset?.pipeline_id)
|
|
const {
|
|
prefix,
|
|
keywords,
|
|
bucket,
|
|
selectedFileKeys,
|
|
fileList,
|
|
} = useDataSourceStoreWithSelector(useShallow(state => ({
|
|
prefix: state.prefix,
|
|
keywords: state.keywords,
|
|
bucket: state.bucket,
|
|
selectedFileKeys: state.selectedFileKeys,
|
|
fileList: state.fileList,
|
|
})))
|
|
const dataSourceStore = useDataSourceStore()
|
|
const [isLoading, setIsLoading] = useState(false)
|
|
|
|
const datasourceNodeRunURL = !isInPipeline
|
|
? `/rag/pipelines/${pipelineId}/workflows/published/datasource/nodes/${nodeId}/run`
|
|
: `/rag/pipelines/${pipelineId}/workflows/draft/datasource/nodes/${nodeId}/run`
|
|
|
|
const getOnlineDriveFiles = useCallback(async (params: {
|
|
prefix?: string[]
|
|
bucket?: string
|
|
startAfter?: string
|
|
fileList?: OnlineDriveFile[]
|
|
}) => {
|
|
const { startAfter, prefix, bucket, fileList } = dataSourceStore.getState()
|
|
const _prefix = params.prefix ?? prefix
|
|
const _bucket = params.bucket ?? bucket
|
|
const _startAfter = params.startAfter ?? startAfter.current
|
|
const _fileList = params.fileList ?? fileList
|
|
const prefixString = _prefix.length > 0 ? `${_prefix.join('/')}/` : ''
|
|
setIsLoading(true)
|
|
ssePost(
|
|
datasourceNodeRunURL,
|
|
{
|
|
body: {
|
|
inputs: {
|
|
prefix: prefixString,
|
|
bucket: _bucket,
|
|
start_after: _startAfter,
|
|
max_keys: 30, // Adjust as needed
|
|
},
|
|
datasource_type: DatasourceType.onlineDrive,
|
|
},
|
|
},
|
|
{
|
|
onDataSourceNodeCompleted: (documentsData: DataSourceNodeCompletedResponse) => {
|
|
const { setFileList, isTruncated } = dataSourceStore.getState()
|
|
const { fileList: newFileList, isTruncated: newIsTruncated } = convertOnlineDriveData(documentsData.data, _prefix, _bucket)
|
|
setFileList([..._fileList, ...newFileList])
|
|
isTruncated.current = newIsTruncated
|
|
setIsLoading(false)
|
|
},
|
|
onDataSourceNodeError: (error: DataSourceNodeErrorResponse) => {
|
|
Toast.notify({
|
|
type: 'error',
|
|
message: error.error,
|
|
})
|
|
setIsLoading(false)
|
|
},
|
|
},
|
|
)
|
|
}, [datasourceNodeRunURL, dataSourceStore])
|
|
|
|
useEffect(() => {
|
|
const {
|
|
setFileList,
|
|
setBucket,
|
|
setPrefix,
|
|
setKeywords,
|
|
setSelectedFileKeys,
|
|
currentNodeIdRef,
|
|
} = dataSourceStore.getState()
|
|
if (nodeId !== currentNodeIdRef.current) {
|
|
setFileList([])
|
|
setBucket('')
|
|
setPrefix([])
|
|
setKeywords('')
|
|
setSelectedFileKeys([])
|
|
currentNodeIdRef.current = nodeId
|
|
getOnlineDriveFiles({
|
|
prefix: [],
|
|
bucket: '',
|
|
fileList: [],
|
|
startAfter: '',
|
|
})
|
|
}
|
|
else {
|
|
// Avoid fetching files when come back from next step
|
|
if (fileList.length > 0) return
|
|
getOnlineDriveFiles({})
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [nodeId])
|
|
|
|
const onlineDriveFileList = useMemo(() => {
|
|
if (keywords)
|
|
return fileList.filter(file => file.key.toLowerCase().includes(keywords.toLowerCase()))
|
|
return fileList
|
|
}, [fileList, keywords])
|
|
|
|
const updateKeywords = useCallback((keywords: string) => {
|
|
const { setKeywords } = dataSourceStore.getState()
|
|
setKeywords(keywords)
|
|
}, [dataSourceStore])
|
|
|
|
const resetKeywords = useCallback(() => {
|
|
const { setKeywords } = dataSourceStore.getState()
|
|
|
|
setKeywords('')
|
|
}, [dataSourceStore])
|
|
|
|
const handleSelectFile = useCallback((file: OnlineDriveFile) => {
|
|
const { selectedFileKeys, setSelectedFileKeys } = dataSourceStore.getState()
|
|
if (file.type === OnlineDriveFileType.bucket) return
|
|
const newSelectedFileList = produce(selectedFileKeys, (draft) => {
|
|
if (draft.includes(file.key)) {
|
|
const index = draft.indexOf(file.key)
|
|
draft.splice(index, 1)
|
|
}
|
|
else {
|
|
if (isInPipeline && draft.length >= 1) return
|
|
draft.push(file.key)
|
|
}
|
|
})
|
|
setSelectedFileKeys(newSelectedFileList)
|
|
}, [dataSourceStore, isInPipeline])
|
|
|
|
const handleOpenFolder = useCallback((file: OnlineDriveFile) => {
|
|
const { prefix, setPrefix, setBucket, setFileList, setSelectedFileKeys } = dataSourceStore.getState()
|
|
if (file.type === OnlineDriveFileType.file) return
|
|
setFileList([])
|
|
if (file.type === OnlineDriveFileType.bucket) {
|
|
setBucket(file.displayName)
|
|
getOnlineDriveFiles({ bucket: file.displayName, fileList: [] })
|
|
}
|
|
else {
|
|
setSelectedFileKeys([])
|
|
const displayName = file.displayName.endsWith('/') ? file.displayName.slice(0, -1) : file.displayName
|
|
const newPrefix = produce(prefix, (draft) => {
|
|
draft.push(displayName)
|
|
})
|
|
setPrefix(newPrefix)
|
|
getOnlineDriveFiles({ prefix: newPrefix, fileList: [] })
|
|
}
|
|
}, [dataSourceStore, getOnlineDriveFiles])
|
|
|
|
return (
|
|
<div className='flex flex-col gap-y-2'>
|
|
<Header
|
|
docTitle='Online Drive Docs'
|
|
docLink='https://docs.dify.ai/'
|
|
/>
|
|
<FileList
|
|
fileList={onlineDriveFileList}
|
|
selectedFileKeys={selectedFileKeys}
|
|
prefix={prefix}
|
|
keywords={keywords}
|
|
bucket={bucket}
|
|
resetKeywords={resetKeywords}
|
|
updateKeywords={updateKeywords}
|
|
searchResultsLength={onlineDriveFileList.length}
|
|
handleSelectFile={handleSelectFile}
|
|
handleOpenFolder={handleOpenFolder}
|
|
isInPipeline={isInPipeline}
|
|
isLoading={isLoading}
|
|
getOnlineDriveFiles={getOnlineDriveFiles}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default OnlineDrive
|