mirror of https://github.com/langgenius/dify.git
Merge remote-tracking branch 'origin/feat/rag-2' into feat/rag-2
This commit is contained in:
commit
334bc8f1a2
|
|
@ -0,0 +1,8 @@
|
|||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.0855 2.50411C10.5056 2.54689 10.8333 2.90198 10.8333 3.33337C10.8333 3.79361 10.4602 4.16671 10 4.16671H6.00017C5.51971 4.16671 5.20926 4.16776 4.97315 4.18705C4.74683 4.20555 4.66278 4.23686 4.62159 4.25785C4.46494 4.33771 4.33768 4.46498 4.25782 4.62162C4.23683 4.66282 4.20551 4.74687 4.18702 4.97319C4.16772 5.2093 4.16667 5.51975 4.16667 6.0002V13.9999C4.16667 14.4803 4.16772 14.7908 4.18702 15.0269C4.20551 15.2532 4.23684 15.3373 4.25782 15.3785C4.33771 15.5351 4.465 15.6624 4.62159 15.7422C4.66278 15.7632 4.74684 15.7945 4.97315 15.813C5.20926 15.8323 5.51971 15.8334 6.00017 15.8334H13.9998C14.4803 15.8334 14.7907 15.8323 15.0269 15.813C15.2532 15.7945 15.3372 15.7632 15.3784 15.7422C15.5351 15.6624 15.6624 15.5351 15.7422 15.3785C15.7632 15.3373 15.7945 15.2532 15.813 15.0269C15.8323 14.7908 15.8333 14.4803 15.8333 13.9999V10C15.8333 9.53981 16.2064 9.16671 16.6667 9.16671C17.1269 9.16671 17.5 9.53981 17.5 10V13.9999C17.5 14.4528 17.5009 14.8431 17.4748 15.1628C17.4478 15.4922 17.388 15.82 17.2274 16.1353C16.9878 16.6055 16.6054 16.9878 16.1353 17.2274C15.82 17.3881 15.4922 17.4479 15.1628 17.4748C14.843 17.5009 14.4528 17.5 13.9998 17.5H6.00017C5.54721 17.5 5.15697 17.5009 4.83724 17.4748C4.50786 17.4479 4.18 17.3881 3.86475 17.2274C3.39449 16.9878 3.01223 16.6054 2.77263 16.1353C2.61199 15.82 2.55216 15.4922 2.52523 15.1628C2.49911 14.8431 2.5 14.4528 2.5 13.9999V6.0002C2.5 5.54725 2.49911 5.15701 2.52523 4.83728C2.55216 4.5079 2.612 4.18003 2.77263 3.86479C3.01227 3.3946 3.39456 3.0123 3.86475 2.77266C4.18 2.61203 4.50786 2.55219 4.83724 2.52527C5.15697 2.49915 5.54721 2.50004 6.00017 2.50004H10L10.0855 2.50411Z" fill="#155AEF"/>
|
||||
<path d="M10.8333 12.5C11.2936 12.5 11.6667 12.8731 11.6667 13.3334C11.6667 13.7936 11.2936 14.1667 10.8333 14.1667H6.66667C6.20643 14.1667 5.83334 13.7936 5.83334 13.3334C5.83334 12.8731 6.20643 12.5 6.66667 12.5H10.8333Z" fill="#155AEF"/>
|
||||
<path d="M8.33334 9.16671C8.79357 9.16671 9.16667 9.5398 9.16667 10C9.16667 10.4603 8.79357 10.8334 8.33334 10.8334H6.66667C6.20643 10.8334 5.83334 10.4603 5.83334 10C5.83334 9.5398 6.20643 9.16671 6.66667 9.16671H8.33334Z" fill="#155AEF"/>
|
||||
<path d="M13.3333 9.16671C13.7936 9.16671 14.1667 9.5398 14.1667 10C14.1667 10.4603 13.7936 10.8334 13.3333 10.8334H10.8333C10.3731 10.8334 10 10.4603 10 10C10 9.5398 10.3731 9.16671 10.8333 9.16671H13.3333Z" fill="#155AEF"/>
|
||||
<path d="M10 5.83337C10.4602 5.83337 10.8333 6.20647 10.8333 6.66671C10.8333 7.12694 10.4602 7.50004 10 7.50004H6.66667C6.20643 7.50004 5.83334 7.12694 5.83334 6.66671C5.83334 6.20647 6.20643 5.83338 6.66667 5.83337H10Z" fill="#155AEF"/>
|
||||
<path d="M15.8333 0.833374C16.2936 0.833374 16.6667 1.20647 16.6667 1.66671V3.33337H18.3333C18.7936 3.33337 19.1667 3.70647 19.1667 4.16671C19.1667 4.62694 18.7936 5.00004 18.3333 5.00004H16.6667V6.66671C16.6667 7.12694 16.2936 7.50004 15.8333 7.50004C15.3731 7.50004 15 7.12694 15 6.66671V5.00004H13.3333C12.8731 5.00004 12.5 4.62694 12.5 4.16671C12.5 3.70647 12.8731 3.33338 13.3333 3.33337H15V1.66671C15 1.20647 15.3731 0.833376 15.8333 0.833374Z" fill="#155AEF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
|
|
@ -0,0 +1,71 @@
|
|||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "20",
|
||||
"height": "20",
|
||||
"viewBox": "0 0 20 20",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M10.0855 2.50411C10.5056 2.54689 10.8333 2.90198 10.8333 3.33337C10.8333 3.79361 10.4602 4.16671 10 4.16671H6.00017C5.51971 4.16671 5.20926 4.16776 4.97315 4.18705C4.74683 4.20555 4.66278 4.23686 4.62159 4.25785C4.46494 4.33771 4.33768 4.46498 4.25782 4.62162C4.23683 4.66282 4.20551 4.74687 4.18702 4.97319C4.16772 5.2093 4.16667 5.51975 4.16667 6.0002V13.9999C4.16667 14.4803 4.16772 14.7908 4.18702 15.0269C4.20551 15.2532 4.23684 15.3373 4.25782 15.3785C4.33771 15.5351 4.465 15.6624 4.62159 15.7422C4.66278 15.7632 4.74684 15.7945 4.97315 15.813C5.20926 15.8323 5.51971 15.8334 6.00017 15.8334H13.9998C14.4803 15.8334 14.7907 15.8323 15.0269 15.813C15.2532 15.7945 15.3372 15.7632 15.3784 15.7422C15.5351 15.6624 15.6624 15.5351 15.7422 15.3785C15.7632 15.3373 15.7945 15.2532 15.813 15.0269C15.8323 14.7908 15.8333 14.4803 15.8333 13.9999V10C15.8333 9.53981 16.2064 9.16671 16.6667 9.16671C17.1269 9.16671 17.5 9.53981 17.5 10V13.9999C17.5 14.4528 17.5009 14.8431 17.4748 15.1628C17.4478 15.4922 17.388 15.82 17.2274 16.1353C16.9878 16.6055 16.6054 16.9878 16.1353 17.2274C15.82 17.3881 15.4922 17.4479 15.1628 17.4748C14.843 17.5009 14.4528 17.5 13.9998 17.5H6.00017C5.54721 17.5 5.15697 17.5009 4.83724 17.4748C4.50786 17.4479 4.18 17.3881 3.86475 17.2274C3.39449 16.9878 3.01223 16.6054 2.77263 16.1353C2.61199 15.82 2.55216 15.4922 2.52523 15.1628C2.49911 14.8431 2.5 14.4528 2.5 13.9999V6.0002C2.5 5.54725 2.49911 5.15701 2.52523 4.83728C2.55216 4.5079 2.612 4.18003 2.77263 3.86479C3.01227 3.3946 3.39456 3.0123 3.86475 2.77266C4.18 2.61203 4.50786 2.55219 4.83724 2.52527C5.15697 2.49915 5.54721 2.50004 6.00017 2.50004H10L10.0855 2.50411Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M10.8333 12.5C11.2936 12.5 11.6667 12.8731 11.6667 13.3334C11.6667 13.7936 11.2936 14.1667 10.8333 14.1667H6.66667C6.20643 14.1667 5.83334 13.7936 5.83334 13.3334C5.83334 12.8731 6.20643 12.5 6.66667 12.5H10.8333Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M8.33334 9.16671C8.79357 9.16671 9.16667 9.5398 9.16667 10C9.16667 10.4603 8.79357 10.8334 8.33334 10.8334H6.66667C6.20643 10.8334 5.83334 10.4603 5.83334 10C5.83334 9.5398 6.20643 9.16671 6.66667 9.16671H8.33334Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M13.3333 9.16671C13.7936 9.16671 14.1667 9.5398 14.1667 10C14.1667 10.4603 13.7936 10.8334 13.3333 10.8334H10.8333C10.3731 10.8334 10 10.4603 10 10C10 9.5398 10.3731 9.16671 10.8333 9.16671H13.3333Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M10 5.83337C10.4602 5.83337 10.8333 6.20647 10.8333 6.66671C10.8333 7.12694 10.4602 7.50004 10 7.50004H6.66667C6.20643 7.50004 5.83334 7.12694 5.83334 6.66671C5.83334 6.20647 6.20643 5.83338 6.66667 5.83337H10Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M15.8333 0.833374C16.2936 0.833374 16.6667 1.20647 16.6667 1.66671V3.33337H18.3333C18.7936 3.33337 19.1667 3.70647 19.1667 4.16671C19.1667 4.62694 18.7936 5.00004 18.3333 5.00004H16.6667V6.66671C16.6667 7.12694 16.2936 7.50004 15.8333 7.50004C15.3731 7.50004 15 7.12694 15 6.66671V5.00004H13.3333C12.8731 5.00004 12.5 4.62694 12.5 4.16671C12.5 3.70647 12.8731 3.33338 13.3333 3.33337H15V1.66671C15 1.20647 15.3731 0.833376 15.8333 0.833374Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "AddChunks"
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './AddChunks.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = (
|
||||
{
|
||||
ref,
|
||||
...props
|
||||
}: React.SVGProps<SVGSVGElement> & {
|
||||
ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
|
||||
},
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />
|
||||
|
||||
Icon.displayName = 'AddChunks'
|
||||
|
||||
export default Icon
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
export { default as AddChunks } from './AddChunks'
|
||||
export { default as ArrowShape } from './ArrowShape'
|
||||
export { default as Chunk } from './Chunk'
|
||||
export { default as Collapse } from './Collapse'
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ const DataSourceOptions = ({
|
|||
useEffect(() => {
|
||||
if (options.length > 0 && !datasourceNodeId)
|
||||
handelSelect(options[0].value)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ const LocalFile = ({
|
|||
const { t } = useTranslation()
|
||||
const { notify } = useContext(ToastContext)
|
||||
const { locale } = useContext(I18n)
|
||||
const fileList = useDataSourceStoreWithSelector(state => state.localFileList)
|
||||
const localFileList = useDataSourceStoreWithSelector(state => state.localFileList)
|
||||
const dataSourceStore = useDataSourceStore()
|
||||
const [dragging, setDragging] = useState(false)
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ const LocalFile = ({
|
|||
const fileUploader = useRef<HTMLInputElement>(null)
|
||||
const fileListRef = useRef<FileItem[]>([])
|
||||
|
||||
const hideUpload = notSupportBatchUpload && fileList.length > 0
|
||||
const hideUpload = notSupportBatchUpload && localFileList.length > 0
|
||||
|
||||
const { data: fileUploadConfigResponse } = useFileUploadConfig()
|
||||
const supportTypesShowNames = useMemo(() => {
|
||||
|
|
@ -179,7 +179,7 @@ const LocalFile = ({
|
|||
if (!files.length)
|
||||
return false
|
||||
|
||||
if (files.length + fileList.length > FILES_NUMBER_LIMIT && !IS_CE_EDITION) {
|
||||
if (files.length + localFileList.length > FILES_NUMBER_LIMIT && !IS_CE_EDITION) {
|
||||
notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.filesNumber', { filesNumber: FILES_NUMBER_LIMIT }) })
|
||||
return false
|
||||
}
|
||||
|
|
@ -193,7 +193,7 @@ const LocalFile = ({
|
|||
updateFileList(newFiles)
|
||||
fileListRef.current = newFiles
|
||||
uploadMultipleFiles(preparedFiles)
|
||||
}, [updateFileList, uploadMultipleFiles, notify, t, fileList])
|
||||
}, [updateFileList, uploadMultipleFiles, notify, t, localFileList])
|
||||
|
||||
const handleDragEnter = (e: DragEvent) => {
|
||||
e.preventDefault()
|
||||
|
|
@ -297,9 +297,9 @@ const LocalFile = ({
|
|||
{dragging && <div ref={dragRef} className='absolute left-0 top-0 h-full w-full' />}
|
||||
</div>
|
||||
)}
|
||||
{fileList.length > 0 && (
|
||||
{localFileList.length > 0 && (
|
||||
<div className='mt-1 flex flex-col gap-y-1'>
|
||||
{fileList.map((fileItem, index) => {
|
||||
{localFileList.map((fileItem, index) => {
|
||||
const isUploading = fileItem.progress >= 0 && fileItem.progress < 100
|
||||
const isError = fileItem.progress === -2
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -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>}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ const Menu = ({
|
|||
{breadcrumbs.map((breadcrumb, index) => {
|
||||
return (
|
||||
<Item
|
||||
key={`${breadcrumb}-${index}`}
|
||||
name={breadcrumb}
|
||||
index={startIndex + index}
|
||||
onBreadcrumbClick={onBreadcrumbClick}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
setFileList([])
|
||||
const { setOnlineDriveFileList, setSelectedFileIds, setBreadcrumbs, setPrefix, setBucket } = dataSourceStore.getState()
|
||||
setOnlineDriveFileList([])
|
||||
setSelectedFileIds([])
|
||||
setBucket('')
|
||||
setBreadcrumbs([])
|
||||
setPrefix([])
|
||||
}, [dataSourceStore])
|
||||
|
||||
const handleClickBucketName = useCallback(() => {
|
||||
const { setFileList, setSelectedFileIds, setPrefix } = dataSourceStore.getState()
|
||||
setFileList([])
|
||||
const { setOnlineDriveFileList, setSelectedFileIds, setBreadcrumbs, setPrefix } = dataSourceStore.getState()
|
||||
setOnlineDriveFileList([])
|
||||
setSelectedFileIds([])
|
||||
setBreadcrumbs([])
|
||||
setPrefix([])
|
||||
}, [dataSourceStore])
|
||||
|
||||
const handleBackToRoot = useCallback(() => {
|
||||
const { setFileList, setSelectedFileIds, setPrefix } = dataSourceStore.getState()
|
||||
setFileList([])
|
||||
const { setOnlineDriveFileList, setSelectedFileIds, setBreadcrumbs, setPrefix } = dataSourceStore.getState()
|
||||
setOnlineDriveFileList([])
|
||||
setSelectedFileIds([])
|
||||
setBreadcrumbs([])
|
||||
setPrefix([])
|
||||
}, [dataSourceStore])
|
||||
|
||||
const handleClickBreadcrumb = useCallback((index: number) => {
|
||||
const { prefix, setFileList, setSelectedFileIds, setPrefix } = dataSourceStore.getState()
|
||||
const { breadcrumbs, prefix, setOnlineDriveFileList, setSelectedFileIds, setBreadcrumbs, setPrefix } = dataSourceStore.getState()
|
||||
const newBreadcrumbs = breadcrumbs.slice(0, index + 1)
|
||||
const newPrefix = prefix.slice(0, index + 1)
|
||||
setFileList([])
|
||||
setOnlineDriveFileList([])
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { DataSourceNodeType } from '@/app/components/workflow/nodes/data-source/types'
|
||||
import Header from '../base/header'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import FileList from './file-list'
|
||||
import type { OnlineDriveFile } from '@/models/pipeline'
|
||||
import { DatasourceType, OnlineDriveFileType } from '@/models/pipeline'
|
||||
|
|
@ -33,23 +33,26 @@ const OnlineDrive = ({
|
|||
const setShowAccountSettingModal = useModalContextSelector(s => s.setShowAccountSettingModal)
|
||||
const {
|
||||
nextPageParameters,
|
||||
breadcrumbs,
|
||||
prefix,
|
||||
keywords,
|
||||
bucket,
|
||||
selectedFileIds,
|
||||
fileList,
|
||||
onlineDriveFileList,
|
||||
currentCredentialId,
|
||||
} = useDataSourceStoreWithSelector(useShallow(state => ({
|
||||
nextPageParameters: state.nextPageParameters,
|
||||
breadcrumbs: state.breadcrumbs,
|
||||
prefix: state.prefix,
|
||||
keywords: state.keywords,
|
||||
bucket: state.bucket,
|
||||
selectedFileIds: state.selectedFileIds,
|
||||
fileList: state.fileList,
|
||||
onlineDriveFileList: state.onlineDriveFileList,
|
||||
currentCredentialId: state.currentCredentialId,
|
||||
})))
|
||||
const dataSourceStore = useDataSourceStore()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const isLoadingRef = useRef(false)
|
||||
|
||||
const { data: dataSourceAuth } = useGetDataSourceAuth({
|
||||
pluginId: nodeData.plugin_id,
|
||||
|
|
@ -61,18 +64,19 @@ const OnlineDrive = ({
|
|||
: `/rag/pipelines/${pipelineId}/workflows/draft/datasource/nodes/${nodeId}/run`
|
||||
|
||||
const getOnlineDriveFiles = useCallback(async () => {
|
||||
const { nextPageParameters, prefix, bucket, fileList, currentCredentialId } = dataSourceStore.getState()
|
||||
const prefixString = prefix.length > 0 ? `${prefix.join('/')}/` : ''
|
||||
if (isLoadingRef.current) return
|
||||
const { nextPageParameters, prefix, bucket, onlineDriveFileList, currentCredentialId } = dataSourceStore.getState()
|
||||
setIsLoading(true)
|
||||
isLoadingRef.current = 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,
|
||||
|
|
@ -80,18 +84,19 @@ const OnlineDrive = ({
|
|||
},
|
||||
{
|
||||
onDataSourceNodeCompleted: (documentsData: DataSourceNodeCompletedResponse) => {
|
||||
const { setFileList, isTruncated, currentNextPageParametersRef, setHasBucket } = dataSourceStore.getState()
|
||||
const { setOnlineDriveFileList, isTruncated, currentNextPageParametersRef, setHasBucket } = dataSourceStore.getState()
|
||||
const {
|
||||
fileList: newFileList,
|
||||
isTruncated: newIsTruncated,
|
||||
nextPageParameters: newNextPageParameters,
|
||||
hasBucket: newHasBucket,
|
||||
} = convertOnlineDriveData(documentsData.data, prefix, bucket)
|
||||
setFileList([...fileList, ...newFileList])
|
||||
} = convertOnlineDriveData(documentsData.data, breadcrumbs, bucket)
|
||||
setOnlineDriveFileList([...onlineDriveFileList, ...newFileList])
|
||||
isTruncated.current = newIsTruncated
|
||||
currentNextPageParametersRef.current = newNextPageParameters
|
||||
setHasBucket(newHasBucket)
|
||||
setIsLoading(false)
|
||||
isLoadingRef.current = false
|
||||
},
|
||||
onDataSourceNodeError: (error: DataSourceNodeErrorResponse) => {
|
||||
Toast.notify({
|
||||
|
|
@ -99,15 +104,17 @@ const OnlineDrive = ({
|
|||
message: error.error,
|
||||
})
|
||||
setIsLoading(false)
|
||||
isLoadingRef.current = false
|
||||
},
|
||||
},
|
||||
)
|
||||
}, [datasourceNodeRunURL, dataSourceStore])
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentCredentialId) return
|
||||
if (isInitialMount) {
|
||||
// Only fetch files on initial mount if fileList is empty
|
||||
if (fileList.length === 0)
|
||||
if (onlineDriveFileList.length === 0)
|
||||
getOnlineDriveFiles()
|
||||
setIsInitialMount(false)
|
||||
}
|
||||
|
|
@ -116,11 +123,11 @@ const OnlineDrive = ({
|
|||
}
|
||||
}, [nextPageParameters, prefix, bucket, currentCredentialId])
|
||||
|
||||
const onlineDriveFileList = useMemo(() => {
|
||||
const filteredOnlineDriveFileList = useMemo(() => {
|
||||
if (keywords)
|
||||
return fileList.filter(file => file.name.toLowerCase().includes(keywords.toLowerCase()))
|
||||
return fileList
|
||||
}, [fileList, keywords])
|
||||
return onlineDriveFileList.filter(file => file.name.toLowerCase().includes(keywords.toLowerCase()))
|
||||
return onlineDriveFileList
|
||||
}, [onlineDriveFileList, keywords])
|
||||
|
||||
const updateKeywords = useCallback((keywords: string) => {
|
||||
const { setKeywords } = dataSourceStore.getState()
|
||||
|
|
@ -150,17 +157,21 @@ const OnlineDrive = ({
|
|||
}, [dataSourceStore, isInPipeline])
|
||||
|
||||
const handleOpenFolder = useCallback((file: OnlineDriveFile) => {
|
||||
const { prefix, setPrefix, setBucket, setFileList, setSelectedFileIds } = dataSourceStore.getState()
|
||||
const { breadcrumbs, prefix, setBreadcrumbs, setPrefix, setBucket, setOnlineDriveFileList, setSelectedFileIds } = dataSourceStore.getState()
|
||||
if (file.type === OnlineDriveFileType.file) return
|
||||
setFileList([])
|
||||
setOnlineDriveFileList([])
|
||||
if (file.type === OnlineDriveFileType.bucket) {
|
||||
setBucket(file.name)
|
||||
}
|
||||
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])
|
||||
|
|
@ -183,14 +194,14 @@ const OnlineDrive = ({
|
|||
credentials={dataSourceAuth?.result || []}
|
||||
/>
|
||||
<FileList
|
||||
fileList={onlineDriveFileList}
|
||||
fileList={filteredOnlineDriveFileList}
|
||||
selectedFileIds={selectedFileIds}
|
||||
prefix={prefix}
|
||||
breadcrumbs={breadcrumbs}
|
||||
keywords={keywords}
|
||||
bucket={bucket}
|
||||
resetKeywords={resetKeywords}
|
||||
updateKeywords={updateKeywords}
|
||||
searchResultsLength={onlineDriveFileList.length}
|
||||
searchResultsLength={filteredOnlineDriveFileList.length}
|
||||
handleSelectFile={handleSelectFile}
|
||||
handleOpenFolder={handleOpenFolder}
|
||||
isInPipeline={isInPipeline}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,16 @@ 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
|
||||
setKeywords: (keywords: string) => void
|
||||
selectedFileIds: string[]
|
||||
setSelectedFileIds: (selectedFileIds: string[]) => void
|
||||
fileList: OnlineDriveFile[]
|
||||
setFileList: (fileList: OnlineDriveFile[]) => void
|
||||
onlineDriveFileList: OnlineDriveFile[]
|
||||
setOnlineDriveFileList: (onlineDriveFileList: OnlineDriveFile[]) => void
|
||||
bucket: string
|
||||
setBucket: (bucket: string) => void
|
||||
nextPageParameters: Record<string, any>
|
||||
|
|
@ -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,
|
||||
|
|
@ -37,12 +43,12 @@ export const createOnlineDriveSlice: StateCreator<OnlineDriveSliceShape> = (set,
|
|||
selectedFileIds,
|
||||
}))
|
||||
const id = selectedFileIds[0]
|
||||
const { fileList, previewOnlineDriveFileRef } = get()
|
||||
previewOnlineDriveFileRef.current = fileList.find(file => file.id === id)
|
||||
const { onlineDriveFileList, previewOnlineDriveFileRef } = get()
|
||||
previewOnlineDriveFileRef.current = onlineDriveFileList.find(file => file.id === id)
|
||||
},
|
||||
fileList: [],
|
||||
setFileList: (fileList: OnlineDriveFile[]) => set(() => ({
|
||||
fileList,
|
||||
onlineDriveFileList: [],
|
||||
setOnlineDriveFileList: (onlineDriveFileList: OnlineDriveFile[]) => set(() => ({
|
||||
onlineDriveFileList,
|
||||
})),
|
||||
bucket: '',
|
||||
setBucket: (bucket: string) => set(() => ({
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ export const useDatasourceOptions = (pipelineNodes: Node<DataSourceNodeType>[])
|
|||
|
||||
export const useLocalFile = () => {
|
||||
const {
|
||||
localFileList: fileList,
|
||||
localFileList,
|
||||
currentLocalFile,
|
||||
} = useDataSourceStoreWithSelector(useShallow(state => ({
|
||||
localFileList: state.localFileList,
|
||||
|
|
@ -73,7 +73,7 @@ export const useLocalFile = () => {
|
|||
})))
|
||||
const dataSourceStore = useDataSourceStore()
|
||||
|
||||
const allFileLoaded = useMemo(() => (fileList.length > 0 && fileList.every(file => file.file.id)), [fileList])
|
||||
const allFileLoaded = useMemo(() => (localFileList.length > 0 && localFileList.every(file => file.file.id)), [localFileList])
|
||||
|
||||
const hidePreviewLocalFile = useCallback(() => {
|
||||
const { setCurrentLocalFile } = dataSourceStore.getState()
|
||||
|
|
@ -81,7 +81,7 @@ export const useLocalFile = () => {
|
|||
}, [dataSourceStore])
|
||||
|
||||
return {
|
||||
fileList,
|
||||
localFileList,
|
||||
allFileLoaded,
|
||||
currentLocalFile,
|
||||
hidePreviewLocalFile,
|
||||
|
|
@ -187,27 +187,27 @@ export const useWebsiteCrawl = () => {
|
|||
|
||||
export const useOnlineDrive = () => {
|
||||
const {
|
||||
fileList,
|
||||
onlineDriveFileList,
|
||||
selectedFileIds,
|
||||
} = useDataSourceStoreWithSelector(useShallow(state => ({
|
||||
fileList: state.fileList,
|
||||
onlineDriveFileList: state.onlineDriveFileList,
|
||||
selectedFileIds: state.selectedFileIds,
|
||||
})))
|
||||
const dataSourceStore = useDataSourceStore()
|
||||
|
||||
const selectedOnlineDriveFileList = useMemo(() => {
|
||||
return selectedFileIds.map(key => fileList.find(item => item.id === key)!)
|
||||
}, [fileList, selectedFileIds])
|
||||
return selectedFileIds.map(key => onlineDriveFileList.find(item => item.id === key)!)
|
||||
}, [onlineDriveFileList, selectedFileIds])
|
||||
|
||||
const clearOnlineDriveData = useCallback(() => {
|
||||
const {
|
||||
setFileList,
|
||||
setOnlineDriveFileList,
|
||||
setBucket,
|
||||
setPrefix,
|
||||
setKeywords,
|
||||
setSelectedFileIds,
|
||||
} = dataSourceStore.getState()
|
||||
setFileList([])
|
||||
setOnlineDriveFileList([])
|
||||
setBucket('')
|
||||
setPrefix([])
|
||||
setKeywords('')
|
||||
|
|
@ -215,7 +215,7 @@ export const useOnlineDrive = () => {
|
|||
}, [dataSourceStore])
|
||||
|
||||
return {
|
||||
fileList,
|
||||
onlineDriveFileList,
|
||||
selectedFileIds,
|
||||
selectedOnlineDriveFileList,
|
||||
clearOnlineDriveData,
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ const CreateFormPipeline = () => {
|
|||
handleBackStep,
|
||||
} = useAddDocumentsSteps()
|
||||
const {
|
||||
fileList,
|
||||
localFileList,
|
||||
allFileLoaded,
|
||||
currentLocalFile,
|
||||
hidePreviewLocalFile,
|
||||
|
|
@ -81,7 +81,7 @@ const CreateFormPipeline = () => {
|
|||
clearWebsiteCrawlData,
|
||||
} = useWebsiteCrawl()
|
||||
const {
|
||||
fileList: onlineDriveFileList,
|
||||
onlineDriveFileList,
|
||||
selectedFileIds,
|
||||
selectedOnlineDriveFileList,
|
||||
clearOnlineDriveData,
|
||||
|
|
@ -107,7 +107,7 @@ const CreateFormPipeline = () => {
|
|||
const nextBtnDisabled = useMemo(() => {
|
||||
if (!datasource) return true
|
||||
if (datasourceType === DatasourceType.localFile)
|
||||
return isShowVectorSpaceFull || !fileList.length || !allFileLoaded
|
||||
return isShowVectorSpaceFull || !localFileList.length || !allFileLoaded
|
||||
if (datasourceType === DatasourceType.onlineDocument)
|
||||
return isShowVectorSpaceFull || !onlineDocuments.length
|
||||
if (datasourceType === DatasourceType.websiteCrawl)
|
||||
|
|
@ -115,7 +115,7 @@ const CreateFormPipeline = () => {
|
|||
if (datasourceType === DatasourceType.onlineDrive)
|
||||
return isShowVectorSpaceFull || !selectedFileIds.length
|
||||
return false
|
||||
}, [datasource, datasourceType, isShowVectorSpaceFull, fileList.length, allFileLoaded, onlineDocuments.length, websitePages.length, selectedFileIds.length])
|
||||
}, [datasource, datasourceType, isShowVectorSpaceFull, localFileList.length, allFileLoaded, onlineDocuments.length, websitePages.length, selectedFileIds.length])
|
||||
|
||||
const fileUploadConfig = useMemo(() => fileUploadConfigResponse ?? {
|
||||
file_size_limit: 15,
|
||||
|
|
@ -285,7 +285,7 @@ const CreateFormPipeline = () => {
|
|||
const {
|
||||
bucket,
|
||||
selectedFileIds,
|
||||
fileList: onlineDriveFileList,
|
||||
onlineDriveFileList,
|
||||
} = dataSourceStore.getState()
|
||||
selectedFileIds.forEach((id) => {
|
||||
const file = onlineDriveFileList.find(file => file.id === id)
|
||||
|
|
@ -354,7 +354,7 @@ const CreateFormPipeline = () => {
|
|||
const handleSelectAll = useCallback(() => {
|
||||
const {
|
||||
onlineDocuments,
|
||||
fileList: onlineDriveFileList,
|
||||
onlineDriveFileList,
|
||||
selectedFileIds,
|
||||
setOnlineDocuments,
|
||||
setSelectedFileIds,
|
||||
|
|
@ -535,7 +535,7 @@ const CreateFormPipeline = () => {
|
|||
<div className='flex h-full flex-col pl-2 pt-2'>
|
||||
<ChunkPreview
|
||||
dataSourceType={datasourceType as DatasourceType}
|
||||
localFiles={fileList.map(file => file.file)}
|
||||
localFiles={localFileList.map(file => file.file)}
|
||||
onlineDocuments={onlineDocuments}
|
||||
websitePages={websitePages}
|
||||
onlineDriveFiles={selectedOnlineDriveFileList}
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ const Line = React.memo(({
|
|||
className,
|
||||
}: LineProps) => {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="2" height="241" viewBox="0 0 2 241" fill="none" className={className}>
|
||||
<path d="M1 0.5L1 240.5" stroke="url(#paint0_linear_1989_74474)"/>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='2' height='241' viewBox='0 0 2 241' fill='none' className={className}>
|
||||
<path d='M1 0.5L1 240.5' stroke='url(#paint0_linear_1989_74474)' />
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_1989_74474" x1="-7.99584" y1="240.5" x2="-7.88094" y2="0.50004" gradientUnits="userSpaceOnUse">
|
||||
<stop stopColor="white" stopOpacity="0.01"/>
|
||||
<stop offset="0.503965" stopColor="#101828" stopOpacity="0.08"/>
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.01"/>
|
||||
<linearGradient id='paint0_linear_1989_74474' x1='-7.99584' y1='240.5' x2='-7.88094' y2='0.50004' gradientUnits='userSpaceOnUse'>
|
||||
<stop stopColor='white' stopOpacity='0.01' />
|
||||
<stop offset='0.503965' stopColor='#101828' stopOpacity='0.08' />
|
||||
<stop offset='1' stopColor='white' stopOpacity='0.01' />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
|
@ -47,8 +47,8 @@ const Empty: FC<IEmptyProps> = ({
|
|||
<div className='flex flex-col items-center'>
|
||||
<div className='relative z-10 flex h-14 w-14 items-center justify-center rounded-xl border border-divider-subtle bg-components-card-bg shadow-lg shadow-shadow-shadow-5'>
|
||||
<RiFileList2Line className='h-6 w-6 text-text-secondary' />
|
||||
<Line className='absolute -right-[1px] top-1/2 -translate-y-1/2' />
|
||||
<Line className='absolute -left-[1px] top-1/2 -translate-y-1/2' />
|
||||
<Line className='absolute -right-px top-1/2 -translate-y-1/2' />
|
||||
<Line className='absolute -left-px top-1/2 -translate-y-1/2' />
|
||||
<Line className='absolute left-1/2 top-0 -translate-x-1/2 -translate-y-1/2 rotate-90' />
|
||||
<Line className='absolute left-1/2 top-full -translate-x-1/2 -translate-y-1/2 rotate-90' />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -110,13 +110,13 @@ export const useOnlineDrive = () => {
|
|||
|
||||
const clearOnlineDriveData = useCallback(() => {
|
||||
const {
|
||||
setFileList,
|
||||
setOnlineDriveFileList,
|
||||
setBucket,
|
||||
setPrefix,
|
||||
setKeywords,
|
||||
setSelectedFileIds,
|
||||
} = dataSourceStore.getState()
|
||||
setFileList([])
|
||||
setOnlineDriveFileList([])
|
||||
setBucket('')
|
||||
setPrefix([])
|
||||
setKeywords('')
|
||||
|
|
|
|||
|
|
@ -104,8 +104,8 @@ const Preparation = () => {
|
|||
})
|
||||
}
|
||||
if (datasourceType === DatasourceType.onlineDrive) {
|
||||
const { bucket, fileList, selectedFileIds } = dataSourceStore.getState()
|
||||
const file = fileList.find(file => file.id === selectedFileIds[0])
|
||||
const { bucket, onlineDriveFileList, selectedFileIds } = dataSourceStore.getState()
|
||||
const file = onlineDriveFileList.find(file => file.id === selectedFileIds[0])
|
||||
datasourceInfoList.push({
|
||||
bucket,
|
||||
id: file?.id,
|
||||
|
|
|
|||
|
|
@ -287,10 +287,9 @@ export const usePipelineRun = () => {
|
|||
)
|
||||
|
||||
const handleStopRun = useCallback((taskId: string) => {
|
||||
const { pipelineId, setShowDebugAndPreviewPanel } = workflowStore.getState()
|
||||
const { pipelineId } = workflowStore.getState()
|
||||
|
||||
stopWorkflowRun(`/rag/pipeline/${pipelineId}/workflow-runs/tasks/${taskId}/stop`)
|
||||
setShowDebugAndPreviewPanel(false)
|
||||
}, [workflowStore])
|
||||
|
||||
const handleRestoreFromPublishedWorkflow = useCallback((publishedWorkflow: VersionHistory) => {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import type {
|
|||
} from '@/app/components/workflow/types'
|
||||
import { useIsChatMode } from './use-workflow'
|
||||
import { useStoreApi } from 'reactflow'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import type { Type } from '../nodes/llm/types'
|
||||
import useMatchSchemaType from '../nodes/_base/components/variable/use-match-schema-type'
|
||||
|
||||
|
|
@ -18,6 +19,11 @@ export const useWorkflowVariables = () => {
|
|||
const workflowStore = useWorkflowStore()
|
||||
const { getMatchedSchemaType } = useMatchSchemaType()
|
||||
|
||||
const buildInTools = useStore(s => s.buildInTools)
|
||||
const customTools = useStore(s => s.customTools)
|
||||
const workflowTools = useStore(s => s.workflowTools)
|
||||
const mcpTools = useStore(s => s.mcpTools)
|
||||
const dataSourceList = useStore(s => s.dataSourceList)
|
||||
const getNodeAvailableVars = useCallback(({
|
||||
parentNode,
|
||||
beforeNodes,
|
||||
|
|
@ -37,11 +43,6 @@ export const useWorkflowVariables = () => {
|
|||
conversationVariables,
|
||||
environmentVariables,
|
||||
ragPipelineVariables,
|
||||
buildInTools,
|
||||
customTools,
|
||||
workflowTools,
|
||||
mcpTools,
|
||||
dataSourceList,
|
||||
} = workflowStore.getState()
|
||||
return toNodeAvailableVars({
|
||||
parentNode,
|
||||
|
|
@ -61,7 +62,7 @@ export const useWorkflowVariables = () => {
|
|||
},
|
||||
getMatchedSchemaType,
|
||||
})
|
||||
}, [t, workflowStore, getMatchedSchemaType])
|
||||
}, [t, workflowStore, getMatchedSchemaType, buildInTools])
|
||||
|
||||
const getCurrentVariableType = useCallback(({
|
||||
parentNode,
|
||||
|
|
@ -71,6 +72,7 @@ export const useWorkflowVariables = () => {
|
|||
availableNodes,
|
||||
isChatMode,
|
||||
isConstant,
|
||||
preferSchemaType,
|
||||
}: {
|
||||
valueSelector: ValueSelector
|
||||
parentNode?: Node | null
|
||||
|
|
@ -79,6 +81,7 @@ export const useWorkflowVariables = () => {
|
|||
availableNodes: any[]
|
||||
isChatMode: boolean
|
||||
isConstant?: boolean
|
||||
preferSchemaType?: boolean
|
||||
}) => {
|
||||
const {
|
||||
conversationVariables,
|
||||
|
|
@ -109,8 +112,9 @@ export const useWorkflowVariables = () => {
|
|||
dataSourceList: dataSourceList ?? [],
|
||||
},
|
||||
getMatchedSchemaType,
|
||||
preferSchemaType,
|
||||
})
|
||||
}, [workflowStore])
|
||||
}, [workflowStore, getVarType, getMatchedSchemaType])
|
||||
|
||||
return {
|
||||
getNodeAvailableVars,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ export const AddVariablePopup = ({
|
|||
hideSearch
|
||||
vars={availableVars}
|
||||
onChange={onSelect}
|
||||
isSupportFileVar
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -825,6 +825,7 @@ export const getVarType = ({
|
|||
ragVariables = [],
|
||||
allPluginInfoList,
|
||||
getMatchedSchemaType,
|
||||
preferSchemaType,
|
||||
}: {
|
||||
valueSelector: ValueSelector
|
||||
parentNode?: Node | null
|
||||
|
|
@ -838,6 +839,7 @@ export const getVarType = ({
|
|||
ragVariables?: RAGPipelineVariable[]
|
||||
allPluginInfoList: Record<string, ToolWithProvider[]>
|
||||
getMatchedSchemaType: (obj: any) => string
|
||||
preferSchemaType?: boolean
|
||||
}): VarType => {
|
||||
if (isConstant)
|
||||
return VarType.string
|
||||
|
|
@ -934,7 +936,7 @@ export const getVarType = ({
|
|||
const isStructuredOutputVar = !!targetVar.children?.schema?.properties
|
||||
if (isStructuredOutputVar) {
|
||||
if (valueSelector.length === 2) { // root
|
||||
return targetVar.alias || VarType.object
|
||||
return (preferSchemaType && targetVar.schemaType) ? targetVar.schemaType : VarType.object
|
||||
}
|
||||
let currProperties = targetVar.children.schema;
|
||||
(valueSelector as ValueSelector).slice(2).forEach((key, i) => {
|
||||
|
|
@ -955,7 +957,7 @@ export const getVarType = ({
|
|||
curr = curr?.find((v: any) => v.variable === key)
|
||||
|
||||
if (isLast) {
|
||||
type = curr?.type
|
||||
type = (preferSchemaType && curr?.schemaType) ? curr?.schemaType : curr?.type
|
||||
}
|
||||
else {
|
||||
if (curr?.type === VarType.object || curr?.type === VarType.file)
|
||||
|
|
|
|||
|
|
@ -288,6 +288,7 @@ const VarReferencePicker: FC<Props> = ({
|
|||
availableNodes,
|
||||
isChatMode,
|
||||
isConstant: !!isConstant,
|
||||
preferSchemaType,
|
||||
})
|
||||
|
||||
const { isEnv, isChatVar, isRagVar, isValidVar, isException } = useMemo(() => {
|
||||
|
|
|
|||
|
|
@ -110,8 +110,8 @@ const useBeforeRunForm = ({
|
|||
}
|
||||
}
|
||||
if (datasourceType === DatasourceType.onlineDrive) {
|
||||
const { bucket, fileList, selectedFileIds } = dataSourceStore.getState()
|
||||
const file = fileList.find(file => file.id === selectedFileIds[0])
|
||||
const { bucket, onlineDriveFileList, selectedFileIds } = dataSourceStore.getState()
|
||||
const file = onlineDriveFileList.find(file => file.id === selectedFileIds[0])
|
||||
datasourceInfo = {
|
||||
bucket,
|
||||
id: file?.id,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import OptionCard from '../option-card'
|
|||
import Selector from './selector'
|
||||
import { useChunkStructure } from './hooks'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Instruction from './instruction'
|
||||
|
||||
type ChunkStructureProps = {
|
||||
chunkStructure?: ChunkStructureEnum
|
||||
|
|
@ -51,20 +52,23 @@ const ChunkStructure = ({
|
|||
}
|
||||
{
|
||||
!chunkStructure && (
|
||||
<Selector
|
||||
options={options}
|
||||
onChange={onChunkStructureChange}
|
||||
readonly={readonly}
|
||||
trigger={(
|
||||
<Button
|
||||
className='w-full'
|
||||
variant='secondary-accent'
|
||||
>
|
||||
<RiAddLine className='mr-1 h-4 w-4' />
|
||||
{t('workflow.nodes.knowledgeBase.chooseChunkStructure')}
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
<>
|
||||
<Selector
|
||||
options={options}
|
||||
onChange={onChunkStructureChange}
|
||||
readonly={readonly}
|
||||
trigger={(
|
||||
<Button
|
||||
className='w-full'
|
||||
variant='secondary-accent'
|
||||
>
|
||||
<RiAddLine className='mr-1 h-4 w-4' />
|
||||
{t('workflow.nodes.knowledgeBase.chooseChunkStructure')}
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
<Instruction className='mt-2' />
|
||||
</>
|
||||
)
|
||||
}
|
||||
</Field>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
import React from 'react'
|
||||
import { AddChunks } from '@/app/components/base/icons/src/vender/knowledge'
|
||||
import Line from './line'
|
||||
import cn from '@/utils/classnames'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
|
||||
type InstructionProps = {
|
||||
className?: string
|
||||
}
|
||||
|
||||
const Instruction = ({
|
||||
className,
|
||||
}: InstructionProps) => {
|
||||
const { t } = useTranslation()
|
||||
const docLink = useDocLink()
|
||||
|
||||
return (
|
||||
<div className={cn('flex flex-col gap-y-2 overflow-hidden rounded-[10px] bg-workflow-process-bg p-4', className)}>
|
||||
<div className='relative flex size-10 items-center justify-center rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg shadow-lg backdrop-blur-[5px]'>
|
||||
<AddChunks className='size-5 text-text-accent' />
|
||||
<Line className='absolute -left-px bottom-[-76px]' type='vertical' />
|
||||
<Line className='absolute -right-px bottom-[-76px]' type='vertical' />
|
||||
<Line className='absolute -top-px right-[-184px]' type='horizontal' />
|
||||
<Line className='absolute -bottom-px right-[-184px]' type='horizontal' />
|
||||
</div>
|
||||
<div className='flex flex-col gap-y-1'>
|
||||
<div className='system-sm-medium text-text-secondary'>
|
||||
{t('workflow.nodes.knowledgeBase.chunkStructureTip.title')}
|
||||
</div>
|
||||
<div className='system-xs-regular'>
|
||||
<p className='text-text-tertiary'>{t('workflow.nodes.knowledgeBase.chunkStructureTip.message')}</p>
|
||||
<a
|
||||
href={docLink('/guides/knowledge-base/create-knowledge-and-upload-documents/chunking-and-cleaning-text')}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-text-accent'
|
||||
>
|
||||
{t('workflow.nodes.knowledgeBase.chunkStructureTip.learnMore')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(Instruction)
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import React from 'react'
|
||||
|
||||
type LineProps = {
|
||||
type?: 'vertical' | 'horizontal'
|
||||
className?: string
|
||||
}
|
||||
|
||||
const Line = ({
|
||||
type = 'vertical',
|
||||
className,
|
||||
}: LineProps) => {
|
||||
if (type === 'vertical') {
|
||||
return (
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='2' height='132' viewBox='0 0 2 132' fill='none' className={className}>
|
||||
<path d='M1 0L1 132' stroke='url(#paint0_linear_10882_18766)' />
|
||||
<defs>
|
||||
<linearGradient id='paint0_linear_10882_18766' x1='-7.99584' y1='132' x2='-7.96108' y2='6.4974e-07' gradientUnits='userSpaceOnUse'>
|
||||
<stop stopColor='var(--color-background-gradient-mask-transparent)' />
|
||||
<stop offset='0.877606' stopColor='var(--color-divider-subtle)' />
|
||||
<stop offset='1' stopColor='var(--color-background-gradient-mask-transparent)' />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='240' height='2' viewBox='0 0 240 2' fill='none' className={className}>
|
||||
<path d='M0 1H240' stroke='url(#paint0_linear_10882_18763)' />
|
||||
<defs>
|
||||
<linearGradient id='paint0_linear_10882_18763' x1='240' y1='9.99584' x2='3.95539e-05' y2='9.88094' gradientUnits='userSpaceOnUse'>
|
||||
<stop stopColor='var(--color-background-gradient-mask-transparent)' />
|
||||
<stop offset='0.9031' stopColor='var(--color-divider-subtle)' />
|
||||
<stop offset='1' stopColor='var(--color-background-gradient-mask-transparent)' />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(Line)
|
||||
|
|
@ -47,7 +47,7 @@ const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
|
|||
} = useConfig(id)
|
||||
|
||||
const filterVar = useCallback((variable: Var) => {
|
||||
if(!data.chunk_structure) return false
|
||||
if (!data.chunk_structure) return false
|
||||
switch (data.chunk_structure) {
|
||||
case ChunkStructureEnum.general:
|
||||
return variable.schemaType === 'general_structure'
|
||||
|
|
@ -55,37 +55,16 @@ const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
|
|||
return variable.schemaType === 'parent_child_structure'
|
||||
case ChunkStructureEnum.question_answer:
|
||||
return variable.schemaType === 'qa_structure'
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}, [data.chunk_structure])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BoxGroupField
|
||||
boxGroupProps={{
|
||||
boxProps: { withBorderBottom: true },
|
||||
}}
|
||||
fieldProps={{
|
||||
fieldTitleProps: {
|
||||
title: t('workflow.nodes.common.inputVars'),
|
||||
},
|
||||
}}
|
||||
>
|
||||
<VarReferencePicker
|
||||
nodeId={id}
|
||||
isShowNodeName
|
||||
value={data.index_chunk_variable_selector}
|
||||
onChange={handleInputVariableChange}
|
||||
readonly={nodesReadOnly}
|
||||
filterVar={filterVar}
|
||||
isFilterFileVar
|
||||
isSupportFileVar={false}
|
||||
preferSchemaType
|
||||
/>
|
||||
</BoxGroupField>
|
||||
<Group
|
||||
className='py-3'
|
||||
withBorderBottom
|
||||
withBorderBottom={!!data.chunk_structure}
|
||||
>
|
||||
<ChunkStructure
|
||||
chunkStructure={data.chunk_structure}
|
||||
|
|
@ -93,11 +72,33 @@ const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
|
|||
readonly={nodesReadOnly}
|
||||
/>
|
||||
</Group>
|
||||
<BoxGroup>
|
||||
<div className='space-y-3'>
|
||||
{
|
||||
data.chunk_structure && (
|
||||
<>
|
||||
{
|
||||
data.chunk_structure && (
|
||||
<>
|
||||
<BoxGroupField
|
||||
boxGroupProps={{
|
||||
boxProps: { withBorderBottom: true },
|
||||
}}
|
||||
fieldProps={{
|
||||
fieldTitleProps: {
|
||||
title: t('workflow.nodes.common.inputVars'),
|
||||
},
|
||||
}}
|
||||
>
|
||||
<VarReferencePicker
|
||||
nodeId={id}
|
||||
isShowNodeName
|
||||
value={data.index_chunk_variable_selector}
|
||||
onChange={handleInputVariableChange}
|
||||
readonly={nodesReadOnly}
|
||||
filterVar={filterVar}
|
||||
isFilterFileVar
|
||||
isSupportFileVar={false}
|
||||
preferSchemaType
|
||||
/>
|
||||
</BoxGroupField>
|
||||
<BoxGroup>
|
||||
<div className='space-y-3'>
|
||||
<IndexMethod
|
||||
chunkStructure={data.chunk_structure}
|
||||
indexMethod={data.indexing_technique}
|
||||
|
|
@ -119,29 +120,29 @@ const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
|
|||
<div className='pt-1'>
|
||||
<Split className='h-[1px]' />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
<RetrievalSetting
|
||||
indexMethod={data.indexing_technique}
|
||||
searchMethod={data.retrieval_model.search_method}
|
||||
onRetrievalSearchMethodChange={handleRetrievalSearchMethodChange}
|
||||
hybridSearchMode={data.retrieval_model.hybridSearchMode}
|
||||
onHybridSearchModeChange={handleHybridSearchModeChange}
|
||||
weightedScore={data.retrieval_model.weights}
|
||||
onWeightedScoreChange={handleWeighedScoreChange}
|
||||
rerankingModel={data.retrieval_model.reranking_model}
|
||||
onRerankingModelChange={handleRerankingModelChange}
|
||||
topK={data.retrieval_model.top_k}
|
||||
onTopKChange={handleTopKChange}
|
||||
scoreThreshold={data.retrieval_model.score_threshold}
|
||||
onScoreThresholdChange={handleScoreThresholdChange}
|
||||
isScoreThresholdEnabled={data.retrieval_model.score_threshold_enabled}
|
||||
onScoreThresholdEnabledChange={handleScoreThresholdEnabledChange}
|
||||
readonly={nodesReadOnly}
|
||||
/>
|
||||
</div>
|
||||
</BoxGroup>
|
||||
<RetrievalSetting
|
||||
indexMethod={data.indexing_technique}
|
||||
searchMethod={data.retrieval_model.search_method}
|
||||
onRetrievalSearchMethodChange={handleRetrievalSearchMethodChange}
|
||||
hybridSearchMode={data.retrieval_model.hybridSearchMode}
|
||||
onHybridSearchModeChange={handleHybridSearchModeChange}
|
||||
weightedScore={data.retrieval_model.weights}
|
||||
onWeightedScoreChange={handleWeighedScoreChange}
|
||||
rerankingModel={data.retrieval_model.reranking_model}
|
||||
onRerankingModelChange={handleRerankingModelChange}
|
||||
topK={data.retrieval_model.top_k}
|
||||
onTopKChange={handleTopKChange}
|
||||
scoreThreshold={data.retrieval_model.score_threshold}
|
||||
onScoreThresholdChange={handleScoreThresholdChange}
|
||||
isScoreThresholdEnabled={data.retrieval_model.score_threshold_enabled}
|
||||
onScoreThresholdEnabledChange={handleScoreThresholdEnabledChange}
|
||||
readonly={nodesReadOnly}
|
||||
/>
|
||||
</div>
|
||||
</BoxGroup>
|
||||
</>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -934,6 +934,11 @@ const translation = {
|
|||
knowledgeBase: {
|
||||
chunkStructure: 'Chunk Structure',
|
||||
chooseChunkStructure: 'Choose a chunk structure',
|
||||
chunkStructureTip: {
|
||||
title: 'Please choose a chunk structure',
|
||||
message: 'After configuring chunk structure, this node will automatically load the remaining configurations.',
|
||||
learnMore: 'Learn more',
|
||||
},
|
||||
changeChunkStructure: 'Change Chunk Structure',
|
||||
aboutRetrieval: 'about retrieval method.',
|
||||
chunkIsRequired: 'Chunk structure is required',
|
||||
|
|
|
|||
|
|
@ -933,6 +933,11 @@ const translation = {
|
|||
knowledgeBase: {
|
||||
chunkStructure: '分段结构',
|
||||
chooseChunkStructure: '选择分段结构',
|
||||
chunkStructureTip: {
|
||||
title: '请选择分段结构',
|
||||
message: '配置完成分段结构后,将自动加载剩余配置。',
|
||||
learnMore: '了解更多',
|
||||
},
|
||||
changeChunkStructure: '更改分段结构',
|
||||
aboutRetrieval: '关于知识检索。',
|
||||
chunkIsRequired: '分段结构是必需的',
|
||||
|
|
|
|||
Loading…
Reference in New Issue