mirror of
https://github.com/langgenius/dify.git
synced 2026-04-29 04:26:30 +08:00
refactor: Add loading state and bucket handling to Online Drive components
This commit is contained in:
parent
d3b17ea567
commit
2ecbcd6a7f
@ -1,21 +1,34 @@
|
|||||||
import React from 'react'
|
import { BucketsGray } from '@/app/components/base/icons/src/public/knowledge/online-drive'
|
||||||
|
import React, { useCallback } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useDataSourceStore } from '../../../store'
|
||||||
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
|
|
||||||
type BreadcrumbsProps = {
|
type BreadcrumbsProps = {
|
||||||
prefix: string[]
|
prefix: string[]
|
||||||
keywords: string
|
keywords: string
|
||||||
|
bucket: string
|
||||||
searchResultsLength: number
|
searchResultsLength: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const Breadcrumbs = ({
|
const Breadcrumbs = ({
|
||||||
prefix,
|
prefix,
|
||||||
keywords,
|
keywords,
|
||||||
|
bucket,
|
||||||
searchResultsLength,
|
searchResultsLength,
|
||||||
}: BreadcrumbsProps) => {
|
}: BreadcrumbsProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const isRoot = prefix.length === 0
|
const { setFileList, setSelectedFileList, setPrefix, setBucket } = useDataSourceStore().getState()
|
||||||
|
const isRoot = prefix.length === 0 && bucket === ''
|
||||||
const isSearching = !!keywords
|
const isSearching = !!keywords
|
||||||
|
|
||||||
|
const handleBackToBucketList = useCallback(() => {
|
||||||
|
setFileList([])
|
||||||
|
setSelectedFileList([])
|
||||||
|
setBucket('')
|
||||||
|
setPrefix([])
|
||||||
|
}, [setBucket, setFileList, setPrefix, setSelectedFileList])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex grow items-center py-1'>
|
<div className='flex grow items-center py-1'>
|
||||||
{isRoot && (
|
{isRoot && (
|
||||||
@ -24,7 +37,18 @@ const Breadcrumbs = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!isRoot && (
|
{!isRoot && (
|
||||||
<div></div>
|
<div className='flex items-center gap-x-0.5'>
|
||||||
|
<Tooltip
|
||||||
|
popupContent={t('datasetPipeline.onlineDrive.breadcrumbs.allBuckets')}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className='flex size-5 cursor-pointer items-center justify-center'
|
||||||
|
onClick={handleBackToBucketList}
|
||||||
|
>
|
||||||
|
<BucketsGray />
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -7,6 +7,7 @@ type HeaderProps = {
|
|||||||
prefix: string[]
|
prefix: string[]
|
||||||
inputValue: string
|
inputValue: string
|
||||||
keywords: string
|
keywords: string
|
||||||
|
bucket: string
|
||||||
searchResultsLength: number
|
searchResultsLength: number
|
||||||
handleInputChange: React.ChangeEventHandler<HTMLInputElement>
|
handleInputChange: React.ChangeEventHandler<HTMLInputElement>
|
||||||
handleResetKeywords: () => void
|
handleResetKeywords: () => void
|
||||||
@ -16,6 +17,7 @@ const Header = ({
|
|||||||
prefix,
|
prefix,
|
||||||
inputValue,
|
inputValue,
|
||||||
keywords,
|
keywords,
|
||||||
|
bucket,
|
||||||
searchResultsLength,
|
searchResultsLength,
|
||||||
handleInputChange,
|
handleInputChange,
|
||||||
handleResetKeywords,
|
handleResetKeywords,
|
||||||
@ -27,6 +29,7 @@ const Header = ({
|
|||||||
<Breadcrumbs
|
<Breadcrumbs
|
||||||
prefix={prefix}
|
prefix={prefix}
|
||||||
keywords={keywords}
|
keywords={keywords}
|
||||||
|
bucket={bucket}
|
||||||
searchResultsLength={searchResultsLength}
|
searchResultsLength={searchResultsLength}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
|
|||||||
@ -9,12 +9,14 @@ type FileListProps = {
|
|||||||
selectedFileList: string[]
|
selectedFileList: string[]
|
||||||
prefix: string[]
|
prefix: string[]
|
||||||
keywords: string
|
keywords: string
|
||||||
|
bucket: string
|
||||||
isInPipeline: boolean
|
isInPipeline: boolean
|
||||||
resetKeywords: () => void
|
resetKeywords: () => void
|
||||||
updateKeywords: (keywords: string) => void
|
updateKeywords: (keywords: string) => void
|
||||||
searchResultsLength: number
|
searchResultsLength: number
|
||||||
handleSelectFile: (file: OnlineDriveFile) => void
|
handleSelectFile: (file: OnlineDriveFile) => void
|
||||||
handleOpenFolder: (file: OnlineDriveFile) => void
|
handleOpenFolder: (file: OnlineDriveFile) => void
|
||||||
|
isLoading: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const FileList = ({
|
const FileList = ({
|
||||||
@ -22,12 +24,14 @@ const FileList = ({
|
|||||||
selectedFileList,
|
selectedFileList,
|
||||||
prefix,
|
prefix,
|
||||||
keywords,
|
keywords,
|
||||||
|
bucket,
|
||||||
resetKeywords,
|
resetKeywords,
|
||||||
updateKeywords,
|
updateKeywords,
|
||||||
searchResultsLength,
|
searchResultsLength,
|
||||||
handleSelectFile,
|
handleSelectFile,
|
||||||
handleOpenFolder,
|
handleOpenFolder,
|
||||||
isInPipeline,
|
isInPipeline,
|
||||||
|
isLoading,
|
||||||
}: FileListProps) => {
|
}: FileListProps) => {
|
||||||
const [inputValue, setInputValue] = useState(keywords)
|
const [inputValue, setInputValue] = useState(keywords)
|
||||||
|
|
||||||
@ -55,6 +59,7 @@ const FileList = ({
|
|||||||
prefix={prefix}
|
prefix={prefix}
|
||||||
inputValue={inputValue}
|
inputValue={inputValue}
|
||||||
keywords={keywords}
|
keywords={keywords}
|
||||||
|
bucket={bucket}
|
||||||
handleInputChange={handleInputChange}
|
handleInputChange={handleInputChange}
|
||||||
searchResultsLength={searchResultsLength}
|
searchResultsLength={searchResultsLength}
|
||||||
handleResetKeywords={handleResetKeywords}
|
handleResetKeywords={handleResetKeywords}
|
||||||
@ -67,6 +72,7 @@ const FileList = ({
|
|||||||
handleOpenFolder={handleOpenFolder}
|
handleOpenFolder={handleOpenFolder}
|
||||||
handleSelectFile={handleSelectFile}
|
handleSelectFile={handleSelectFile}
|
||||||
isInPipeline={isInPipeline}
|
isInPipeline={isInPipeline}
|
||||||
|
isLoading={isLoading}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -2,12 +2,15 @@ import type { OnlineDriveFile } from '@/models/pipeline'
|
|||||||
import Item from './item'
|
import Item from './item'
|
||||||
import EmptyFolder from './empty-folder'
|
import EmptyFolder from './empty-folder'
|
||||||
import EmptySearchResult from './empty-search-result'
|
import EmptySearchResult from './empty-search-result'
|
||||||
|
import Loading from '@/app/components/base/loading'
|
||||||
|
import { RiLoader2Line } from '@remixicon/react'
|
||||||
|
|
||||||
type FileListProps = {
|
type FileListProps = {
|
||||||
fileList: OnlineDriveFile[]
|
fileList: OnlineDriveFile[]
|
||||||
selectedFileList: string[]
|
selectedFileList: string[]
|
||||||
keywords: string
|
keywords: string
|
||||||
isInPipeline: boolean
|
isInPipeline: boolean
|
||||||
|
isLoading: boolean
|
||||||
handleResetKeywords: () => void
|
handleResetKeywords: () => void
|
||||||
handleSelectFile: (file: OnlineDriveFile) => void
|
handleSelectFile: (file: OnlineDriveFile) => void
|
||||||
handleOpenFolder: (file: OnlineDriveFile) => void
|
handleOpenFolder: (file: OnlineDriveFile) => void
|
||||||
@ -21,12 +24,20 @@ const List = ({
|
|||||||
handleSelectFile,
|
handleSelectFile,
|
||||||
handleOpenFolder,
|
handleOpenFolder,
|
||||||
isInPipeline,
|
isInPipeline,
|
||||||
|
isLoading,
|
||||||
}: FileListProps) => {
|
}: FileListProps) => {
|
||||||
const isEmptyFolder = fileList.length === 0 && keywords.length === 0
|
const isAllLoading = isLoading && fileList.length === 0 && keywords.length === 0
|
||||||
const isSearchResultEmpty = fileList.length === 0 && keywords.length > 0
|
const isPartLoading = isLoading && fileList.length > 0
|
||||||
|
const isEmptyFolder = !isLoading && fileList.length === 0 && keywords.length === 0
|
||||||
|
const isSearchResultEmpty = !isLoading && fileList.length === 0 && keywords.length > 0
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='grow overflow-hidden p-1 pt-0'>
|
<div className='grow overflow-hidden p-1 pt-0'>
|
||||||
|
{
|
||||||
|
isAllLoading && (
|
||||||
|
<Loading type='app' />
|
||||||
|
)
|
||||||
|
}
|
||||||
{
|
{
|
||||||
isEmptyFolder && (
|
isEmptyFolder && (
|
||||||
<EmptyFolder />
|
<EmptyFolder />
|
||||||
@ -54,6 +65,13 @@ const List = ({
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
isPartLoading && (
|
||||||
|
<div className='flex items-center justify-center py-2'>
|
||||||
|
<RiLoader2Line className='animation-spin size-4 text-text-tertiary' />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import type { DataSourceNodeType } from '@/app/components/workflow/nodes/data-source/types'
|
import type { DataSourceNodeType } from '@/app/components/workflow/nodes/data-source/types'
|
||||||
import Header from './header'
|
import Header from './header'
|
||||||
import { useCallback, useEffect } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import FileList from './file-list'
|
import FileList from './file-list'
|
||||||
import type { OnlineDriveFile } from '@/models/pipeline'
|
import type { OnlineDriveFile } from '@/models/pipeline'
|
||||||
import { DatasourceType, OnlineDriveFileType } from '@/models/pipeline'
|
import { DatasourceType, OnlineDriveFileType } from '@/models/pipeline'
|
||||||
@ -36,12 +36,14 @@ const OnlineDrive = ({
|
|||||||
const setSelectedFileList = useDataSourceStoreWithSelector(state => state.setSelectedFileList)
|
const setSelectedFileList = useDataSourceStoreWithSelector(state => state.setSelectedFileList)
|
||||||
const fileList = useDataSourceStoreWithSelector(state => state.fileList)
|
const fileList = useDataSourceStoreWithSelector(state => state.fileList)
|
||||||
const setFileList = useDataSourceStoreWithSelector(state => state.setFileList)
|
const setFileList = useDataSourceStoreWithSelector(state => state.setFileList)
|
||||||
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
|
||||||
const datasourceNodeRunURL = !isInPipeline
|
const datasourceNodeRunURL = !isInPipeline
|
||||||
? `/rag/pipelines/${pipelineId}/workflows/published/datasource/nodes/${nodeId}/run`
|
? `/rag/pipelines/${pipelineId}/workflows/published/datasource/nodes/${nodeId}/run`
|
||||||
: `/rag/pipelines/${pipelineId}/workflows/draft/datasource/nodes/${nodeId}/run`
|
: `/rag/pipelines/${pipelineId}/workflows/draft/datasource/nodes/${nodeId}/run`
|
||||||
|
|
||||||
const getOnlineDrive = useCallback(async () => {
|
const getOnlineDrive = useCallback(async () => {
|
||||||
|
setIsLoading(true)
|
||||||
ssePost(
|
ssePost(
|
||||||
datasourceNodeRunURL,
|
datasourceNodeRunURL,
|
||||||
{
|
{
|
||||||
@ -59,12 +61,14 @@ const OnlineDrive = ({
|
|||||||
onDataSourceNodeCompleted: (documentsData: DataSourceNodeCompletedResponse) => {
|
onDataSourceNodeCompleted: (documentsData: DataSourceNodeCompletedResponse) => {
|
||||||
const newFileList = convertOnlineDriveDataToFileList(documentsData.data)
|
const newFileList = convertOnlineDriveDataToFileList(documentsData.data)
|
||||||
setFileList([...fileList, ...newFileList])
|
setFileList([...fileList, ...newFileList])
|
||||||
|
setIsLoading(false)
|
||||||
},
|
},
|
||||||
onDataSourceNodeError: (error: DataSourceNodeErrorResponse) => {
|
onDataSourceNodeError: (error: DataSourceNodeErrorResponse) => {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: error.error,
|
message: error.error,
|
||||||
})
|
})
|
||||||
|
setIsLoading(false)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -123,12 +127,14 @@ const OnlineDrive = ({
|
|||||||
selectedFileList={selectedFileList}
|
selectedFileList={selectedFileList}
|
||||||
prefix={prefix}
|
prefix={prefix}
|
||||||
keywords={keywords}
|
keywords={keywords}
|
||||||
|
bucket={bucket}
|
||||||
resetKeywords={resetPrefix}
|
resetKeywords={resetPrefix}
|
||||||
updateKeywords={updateKeywords}
|
updateKeywords={updateKeywords}
|
||||||
searchResultsLength={fileList.length}
|
searchResultsLength={fileList.length}
|
||||||
handleSelectFile={handleSelectFile}
|
handleSelectFile={handleSelectFile}
|
||||||
handleOpenFolder={handleOpenFolder}
|
handleOpenFolder={handleOpenFolder}
|
||||||
isInPipeline={isInPipeline}
|
isInPipeline={isInPipeline}
|
||||||
|
isLoading={isLoading}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user