mirror of https://github.com/langgenius/dify.git
refactor: Refactor online drive breadcrumbs navigation
This commit is contained in:
parent
4403a26f37
commit
843b14ccc6
|
|
@ -70,7 +70,6 @@ const OnlineDocuments = ({
|
|||
|
||||
const getOnlineDocuments = useCallback(async () => {
|
||||
const { currentCredentialId } = dataSourceStore.getState()
|
||||
if (!currentCredentialId) return
|
||||
ssePost(
|
||||
datasourceNodeRunURL,
|
||||
{
|
||||
|
|
@ -96,6 +95,7 @@ const OnlineDocuments = ({
|
|||
}, [dataSourceStore, datasourceNodeRunURL])
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentCredentialId) return
|
||||
getOnlineDocuments()
|
||||
}, [currentCredentialId])
|
||||
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@ import cn from '@/utils/classnames'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
type DriveProps = {
|
||||
prefix: string[]
|
||||
breadcrumbs: string[]
|
||||
handleBackToRoot: () => void
|
||||
}
|
||||
|
||||
const Drive = ({
|
||||
prefix,
|
||||
breadcrumbs,
|
||||
handleBackToRoot,
|
||||
}: DriveProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
|
@ -19,15 +19,15 @@ const Drive = ({
|
|||
type='button'
|
||||
className={cn(
|
||||
'max-w-full shrink truncate rounded-md px-[5px] py-1',
|
||||
prefix.length > 0 && 'system-sm-regular text-text-tertiary hover:bg-state-base-hover',
|
||||
prefix.length === 0 && 'system-sm-medium text-text-secondary',
|
||||
breadcrumbs.length > 0 && 'system-sm-regular text-text-tertiary hover:bg-state-base-hover',
|
||||
breadcrumbs.length === 0 && 'system-sm-medium text-text-secondary',
|
||||
)}
|
||||
onClick={handleBackToRoot}
|
||||
disabled={prefix.length === 0}
|
||||
disabled={breadcrumbs.length === 0}
|
||||
>
|
||||
{t('datasetPipeline.onlineDrive.breadcrumbs.allFiles')}
|
||||
</button>
|
||||
{prefix.length > 0 && <span className='system-xs-regular text-divider-deep'>/</span>}
|
||||
{breadcrumbs.length > 0 && <span className='system-xs-regular text-divider-deep'>/</span>}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import Dropdown from './dropdown'
|
|||
import Drive from './drive'
|
||||
|
||||
type BreadcrumbsProps = {
|
||||
prefix: string[]
|
||||
breadcrumbs: string[]
|
||||
keywords: string
|
||||
bucket: string
|
||||
searchResultsLength: number
|
||||
|
|
@ -15,7 +15,7 @@ type BreadcrumbsProps = {
|
|||
}
|
||||
|
||||
const Breadcrumbs = ({
|
||||
prefix,
|
||||
breadcrumbs,
|
||||
keywords,
|
||||
bucket,
|
||||
searchResultsLength,
|
||||
|
|
@ -25,52 +25,57 @@ const Breadcrumbs = ({
|
|||
const dataSourceStore = useDataSourceStore()
|
||||
const hasBucket = useDataSourceStoreWithSelector(s => s.hasBucket)
|
||||
const showSearchResult = !!keywords && searchResultsLength > 0
|
||||
const showBucketListTitle = prefix.length === 0 && hasBucket && bucket === ''
|
||||
const showBucketListTitle = breadcrumbs.length === 0 && hasBucket && bucket === ''
|
||||
|
||||
const displayBreadcrumbNum = useMemo(() => {
|
||||
const num = isInPipeline ? 2 : 3
|
||||
return bucket ? num - 1 : num
|
||||
}, [isInPipeline, bucket])
|
||||
|
||||
const breadcrumbs = useMemo(() => {
|
||||
const prefixToDisplay = prefix.slice(0, displayBreadcrumbNum - 1)
|
||||
const collapsedBreadcrumbs = prefix.slice(displayBreadcrumbNum - 1, prefix.length - 1)
|
||||
const breadcrumbsConfig = useMemo(() => {
|
||||
const prefixToDisplay = breadcrumbs.slice(0, displayBreadcrumbNum - 1)
|
||||
const collapsedBreadcrumbs = breadcrumbs.slice(displayBreadcrumbNum - 1, breadcrumbs.length - 1)
|
||||
return {
|
||||
original: prefix,
|
||||
needCollapsed: prefix.length > displayBreadcrumbNum,
|
||||
original: breadcrumbs,
|
||||
needCollapsed: breadcrumbs.length > displayBreadcrumbNum,
|
||||
prefixBreadcrumbs: prefixToDisplay,
|
||||
collapsedBreadcrumbs,
|
||||
lastBreadcrumb: prefix[prefix.length - 1],
|
||||
lastBreadcrumb: breadcrumbs[breadcrumbs.length - 1],
|
||||
}
|
||||
}, [displayBreadcrumbNum, prefix])
|
||||
}, [displayBreadcrumbNum, breadcrumbs])
|
||||
|
||||
const handleBackToBucketList = useCallback(() => {
|
||||
const { setFileList, setSelectedFileIds, setPrefix, setBucket } = dataSourceStore.getState()
|
||||
const { setFileList, setSelectedFileIds, setBreadcrumbs, setPrefix, setBucket } = dataSourceStore.getState()
|
||||
setFileList([])
|
||||
setSelectedFileIds([])
|
||||
setBucket('')
|
||||
setBreadcrumbs([])
|
||||
setPrefix([])
|
||||
}, [dataSourceStore])
|
||||
|
||||
const handleClickBucketName = useCallback(() => {
|
||||
const { setFileList, setSelectedFileIds, setPrefix } = dataSourceStore.getState()
|
||||
const { setFileList, setSelectedFileIds, setBreadcrumbs, setPrefix } = dataSourceStore.getState()
|
||||
setFileList([])
|
||||
setSelectedFileIds([])
|
||||
setBreadcrumbs([])
|
||||
setPrefix([])
|
||||
}, [dataSourceStore])
|
||||
|
||||
const handleBackToRoot = useCallback(() => {
|
||||
const { setFileList, setSelectedFileIds, setPrefix } = dataSourceStore.getState()
|
||||
const { setFileList, setSelectedFileIds, setBreadcrumbs, setPrefix } = dataSourceStore.getState()
|
||||
setFileList([])
|
||||
setSelectedFileIds([])
|
||||
setBreadcrumbs([])
|
||||
setPrefix([])
|
||||
}, [dataSourceStore])
|
||||
|
||||
const handleClickBreadcrumb = useCallback((index: number) => {
|
||||
const { prefix, setFileList, setSelectedFileIds, setPrefix } = dataSourceStore.getState()
|
||||
const { breadcrumbs, prefix, setFileList, setSelectedFileIds, setBreadcrumbs, setPrefix } = dataSourceStore.getState()
|
||||
const newBreadcrumbs = breadcrumbs.slice(0, index + 1)
|
||||
const newPrefix = prefix.slice(0, index + 1)
|
||||
setFileList([])
|
||||
setSelectedFileIds([])
|
||||
setBreadcrumbs(newBreadcrumbs)
|
||||
setPrefix(newPrefix)
|
||||
}, [dataSourceStore])
|
||||
|
||||
|
|
@ -80,7 +85,7 @@ const Breadcrumbs = ({
|
|||
<div className='system-sm-medium text-test-secondary px-[5px]'>
|
||||
{t('datasetPipeline.onlineDrive.breadcrumbs.searchResult', {
|
||||
searchResultsLength,
|
||||
folderName: prefix.length > 0 ? prefix[prefix.length - 1] : bucket,
|
||||
folderName: breadcrumbs.length > 0 ? breadcrumbs[breadcrumbs.length - 1] : bucket,
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -96,21 +101,21 @@ const Breadcrumbs = ({
|
|||
bucketName={bucket}
|
||||
handleBackToBucketList={handleBackToBucketList}
|
||||
handleClickBucketName={handleClickBucketName}
|
||||
isActive={prefix.length === 0}
|
||||
disabled={prefix.length === 0}
|
||||
showSeparator={prefix.length > 0}
|
||||
isActive={breadcrumbs.length === 0}
|
||||
disabled={breadcrumbs.length === 0}
|
||||
showSeparator={breadcrumbs.length > 0}
|
||||
/>
|
||||
)}
|
||||
{!hasBucket && (
|
||||
<Drive
|
||||
prefix={prefix}
|
||||
breadcrumbs={breadcrumbs}
|
||||
handleBackToRoot={handleBackToRoot}
|
||||
/>
|
||||
)}
|
||||
{!breadcrumbs.needCollapsed && (
|
||||
{!breadcrumbsConfig.needCollapsed && (
|
||||
<>
|
||||
{breadcrumbs.original.map((breadcrumb, index) => {
|
||||
const isLast = index === breadcrumbs.original.length - 1
|
||||
{breadcrumbsConfig.original.map((breadcrumb, index) => {
|
||||
const isLast = index === breadcrumbsConfig.original.length - 1
|
||||
return (
|
||||
<BreadcrumbItem
|
||||
key={`${breadcrumb}-${index}`}
|
||||
|
|
@ -125,9 +130,9 @@ const Breadcrumbs = ({
|
|||
})}
|
||||
</>
|
||||
)}
|
||||
{breadcrumbs.needCollapsed && (
|
||||
{breadcrumbsConfig.needCollapsed && (
|
||||
<>
|
||||
{breadcrumbs.prefixBreadcrumbs.map((breadcrumb, index) => {
|
||||
{breadcrumbsConfig.prefixBreadcrumbs.map((breadcrumb, index) => {
|
||||
return (
|
||||
<BreadcrumbItem
|
||||
key={`${breadcrumb}-${index}`}
|
||||
|
|
@ -138,14 +143,14 @@ const Breadcrumbs = ({
|
|||
)
|
||||
})}
|
||||
<Dropdown
|
||||
startIndex={breadcrumbs.prefixBreadcrumbs.length}
|
||||
breadcrumbs={breadcrumbs.collapsedBreadcrumbs}
|
||||
startIndex={breadcrumbsConfig.prefixBreadcrumbs.length}
|
||||
breadcrumbs={breadcrumbsConfig.collapsedBreadcrumbs}
|
||||
onBreadcrumbClick={handleClickBreadcrumb}
|
||||
/>
|
||||
<BreadcrumbItem
|
||||
index={prefix.length - 1}
|
||||
index={breadcrumbs.length - 1}
|
||||
handleClick={handleClickBreadcrumb}
|
||||
name={breadcrumbs.lastBreadcrumb}
|
||||
name={breadcrumbsConfig.lastBreadcrumb}
|
||||
isActive={true}
|
||||
disabled={true}
|
||||
showSeparator={false}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import Input from '@/app/components/base/input'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
type HeaderProps = {
|
||||
prefix: string[]
|
||||
breadcrumbs: string[]
|
||||
inputValue: string
|
||||
keywords: string
|
||||
bucket: string
|
||||
|
|
@ -15,7 +15,7 @@ type HeaderProps = {
|
|||
}
|
||||
|
||||
const Header = ({
|
||||
prefix,
|
||||
breadcrumbs,
|
||||
inputValue,
|
||||
keywords,
|
||||
bucket,
|
||||
|
|
@ -29,7 +29,7 @@ const Header = ({
|
|||
return (
|
||||
<div className='flex items-center gap-x-2 bg-components-panel-bg p-1 pl-3'>
|
||||
<Breadcrumbs
|
||||
prefix={prefix}
|
||||
breadcrumbs={breadcrumbs}
|
||||
keywords={keywords}
|
||||
bucket={bucket}
|
||||
searchResultsLength={searchResultsLength}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { useDebounceFn } from 'ahooks'
|
|||
type FileListProps = {
|
||||
fileList: OnlineDriveFile[]
|
||||
selectedFileIds: string[]
|
||||
prefix: string[]
|
||||
breadcrumbs: string[]
|
||||
keywords: string
|
||||
bucket: string
|
||||
isInPipeline: boolean
|
||||
|
|
@ -22,7 +22,7 @@ type FileListProps = {
|
|||
const FileList = ({
|
||||
fileList,
|
||||
selectedFileIds,
|
||||
prefix,
|
||||
breadcrumbs,
|
||||
keywords,
|
||||
bucket,
|
||||
resetKeywords,
|
||||
|
|
@ -56,7 +56,7 @@ const FileList = ({
|
|||
return (
|
||||
<div className='flex h-[400px] flex-col overflow-hidden rounded-xl border border-components-panel-border bg-components-panel-bg shadow-xs shadow-shadow-shadow-3'>
|
||||
<Header
|
||||
prefix={prefix}
|
||||
breadcrumbs={breadcrumbs}
|
||||
inputValue={inputValue}
|
||||
keywords={keywords}
|
||||
bucket={bucket}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ const List = ({
|
|||
observerRef.current.observe(anchorRef.current)
|
||||
}
|
||||
return () => observerRef.current?.disconnect()
|
||||
}, [anchorRef])
|
||||
}, [anchorRef, isLoading])
|
||||
|
||||
const isAllLoading = isLoading && fileList.length === 0 && keywords.length === 0
|
||||
const isPartialLoading = isLoading && fileList.length > 0
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ const OnlineDrive = ({
|
|||
const setShowAccountSettingModal = useModalContextSelector(s => s.setShowAccountSettingModal)
|
||||
const {
|
||||
nextPageParameters,
|
||||
breadcrumbs,
|
||||
prefix,
|
||||
keywords,
|
||||
bucket,
|
||||
|
|
@ -41,6 +42,7 @@ const OnlineDrive = ({
|
|||
currentCredentialId,
|
||||
} = useDataSourceStoreWithSelector(useShallow(state => ({
|
||||
nextPageParameters: state.nextPageParameters,
|
||||
breadcrumbs: state.breadcrumbs,
|
||||
prefix: state.prefix,
|
||||
keywords: state.keywords,
|
||||
bucket: state.bucket,
|
||||
|
|
@ -62,17 +64,16 @@ const OnlineDrive = ({
|
|||
|
||||
const getOnlineDriveFiles = useCallback(async () => {
|
||||
const { nextPageParameters, prefix, bucket, fileList, currentCredentialId } = dataSourceStore.getState()
|
||||
const prefixString = prefix.length > 0 ? `${prefix.join('/')}/` : ''
|
||||
setIsLoading(true)
|
||||
ssePost(
|
||||
datasourceNodeRunURL,
|
||||
{
|
||||
body: {
|
||||
inputs: {
|
||||
prefix: prefixString,
|
||||
prefix: prefix[prefix.length - 1],
|
||||
bucket,
|
||||
next_page_parameters: nextPageParameters,
|
||||
max_keys: 30, // Adjust as needed
|
||||
max_keys: 30,
|
||||
},
|
||||
datasource_type: DatasourceType.onlineDrive,
|
||||
credential_id: currentCredentialId,
|
||||
|
|
@ -86,7 +87,7 @@ const OnlineDrive = ({
|
|||
isTruncated: newIsTruncated,
|
||||
nextPageParameters: newNextPageParameters,
|
||||
hasBucket: newHasBucket,
|
||||
} = convertOnlineDriveData(documentsData.data, prefix, bucket)
|
||||
} = convertOnlineDriveData(documentsData.data, breadcrumbs, bucket)
|
||||
setFileList([...fileList, ...newFileList])
|
||||
isTruncated.current = newIsTruncated
|
||||
currentNextPageParametersRef.current = newNextPageParameters
|
||||
|
|
@ -105,6 +106,7 @@ const OnlineDrive = ({
|
|||
}, [datasourceNodeRunURL, dataSourceStore])
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentCredentialId) return
|
||||
if (isInitialMount) {
|
||||
// Only fetch files on initial mount if fileList is empty
|
||||
if (fileList.length === 0)
|
||||
|
|
@ -150,7 +152,7 @@ const OnlineDrive = ({
|
|||
}, [dataSourceStore, isInPipeline])
|
||||
|
||||
const handleOpenFolder = useCallback((file: OnlineDriveFile) => {
|
||||
const { prefix, setPrefix, setBucket, setFileList, setSelectedFileIds } = dataSourceStore.getState()
|
||||
const { breadcrumbs, setBreadcrumbs, setPrefix, setBucket, setFileList, setSelectedFileIds } = dataSourceStore.getState()
|
||||
if (file.type === OnlineDriveFileType.file) return
|
||||
setFileList([])
|
||||
if (file.type === OnlineDriveFileType.bucket) {
|
||||
|
|
@ -158,9 +160,13 @@ const OnlineDrive = ({
|
|||
}
|
||||
else {
|
||||
setSelectedFileIds([])
|
||||
const newPrefix = produce(prefix, (draft) => {
|
||||
const newBreadcrumbs = produce(breadcrumbs, (draft) => {
|
||||
draft.push(file.name)
|
||||
})
|
||||
const newPrefix = produce(prefix, (draft) => {
|
||||
draft.push(file.id)
|
||||
})
|
||||
setBreadcrumbs(newBreadcrumbs)
|
||||
setPrefix(newPrefix)
|
||||
}
|
||||
}, [dataSourceStore, getOnlineDriveFiles])
|
||||
|
|
@ -185,7 +191,7 @@ const OnlineDrive = ({
|
|||
<FileList
|
||||
fileList={onlineDriveFileList}
|
||||
selectedFileIds={selectedFileIds}
|
||||
prefix={prefix}
|
||||
breadcrumbs={breadcrumbs}
|
||||
keywords={keywords}
|
||||
bucket={bucket}
|
||||
resetKeywords={resetKeywords}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import type { StateCreator } from 'zustand'
|
|||
import type { OnlineDriveFile } from '@/models/pipeline'
|
||||
|
||||
export type OnlineDriveSliceShape = {
|
||||
breadcrumbs: string[]
|
||||
setBreadcrumbs: (breadcrumbs: string[]) => void
|
||||
prefix: string[]
|
||||
setPrefix: (prefix: string[]) => void
|
||||
keywords: string
|
||||
|
|
@ -23,6 +25,10 @@ export type OnlineDriveSliceShape = {
|
|||
|
||||
export const createOnlineDriveSlice: StateCreator<OnlineDriveSliceShape> = (set, get) => {
|
||||
return ({
|
||||
breadcrumbs: [],
|
||||
setBreadcrumbs: (breadcrumbs: string[]) => set(() => ({
|
||||
breadcrumbs,
|
||||
})),
|
||||
prefix: [],
|
||||
setPrefix: (prefix: string[]) => set(() => ({
|
||||
prefix,
|
||||
|
|
|
|||
Loading…
Reference in New Issue