From 843b14ccc63de153118b25cd5664acfb53ae4d74 Mon Sep 17 00:00:00 2001 From: twwu Date: Thu, 28 Aug 2025 10:56:51 +0800 Subject: [PATCH 1/6] refactor: Refactor online drive breadcrumbs navigation --- .../data-source/online-documents/index.tsx | 2 +- .../file-list/header/breadcrumbs/drive.tsx | 12 ++-- .../file-list/header/breadcrumbs/index.tsx | 61 ++++++++++--------- .../online-drive/file-list/header/index.tsx | 6 +- .../online-drive/file-list/index.tsx | 6 +- .../online-drive/file-list/list/index.tsx | 2 +- .../data-source/online-drive/index.tsx | 20 +++--- .../data-source/store/slices/online-drive.ts | 6 ++ 8 files changed, 66 insertions(+), 49 deletions(-) diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-documents/index.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-documents/index.tsx index 944752fc04..92fe6f2e19 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-documents/index.tsx +++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-documents/index.tsx @@ -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]) diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/drive.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/drive.tsx index b7115616bb..096dc5c232 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/drive.tsx +++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/drive.tsx @@ -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')} - {prefix.length > 0 && /} + {breadcrumbs.length > 0 && /} ) } diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/index.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/index.tsx index 52d9846617..0b017bb992 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/index.tsx +++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/index.tsx @@ -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 = ({
{t('datasetPipeline.onlineDrive.breadcrumbs.searchResult', { searchResultsLength, - folderName: prefix.length > 0 ? prefix[prefix.length - 1] : bucket, + folderName: breadcrumbs.length > 0 ? breadcrumbs[breadcrumbs.length - 1] : bucket, })}
)} @@ -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 && ( )} - {!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 ( )} - {breadcrumbs.needCollapsed && ( + {breadcrumbsConfig.needCollapsed && ( <> - {breadcrumbs.prefixBreadcrumbs.map((breadcrumb, index) => { + {breadcrumbsConfig.prefixBreadcrumbs.map((breadcrumb, index) => { return (
observerRef.current?.disconnect() - }, [anchorRef]) + }, [anchorRef, isLoading]) const isAllLoading = isLoading && fileList.length === 0 && keywords.length === 0 const isPartialLoading = isLoading && fileList.length > 0 diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/index.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/index.tsx index e15dac89fe..e048d87dc0 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/index.tsx +++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/index.tsx @@ -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 = ({ void prefix: string[] setPrefix: (prefix: string[]) => void keywords: string @@ -23,6 +25,10 @@ export type OnlineDriveSliceShape = { export const createOnlineDriveSlice: StateCreator = (set, get) => { return ({ + breadcrumbs: [], + setBreadcrumbs: (breadcrumbs: string[]) => set(() => ({ + breadcrumbs, + })), prefix: [], setPrefix: (prefix: string[]) => set(() => ({ prefix, From 048feb4165e4a30971a6b2b67586ce5eedef5372 Mon Sep 17 00:00:00 2001 From: twwu Date: Thu, 28 Aug 2025 13:47:20 +0800 Subject: [PATCH 2/6] refactor: update local file and online drive state management in create-from-pipeline components --- .../data-source-options/index.tsx | 1 - .../data-source/local-file/index.tsx | 12 +++---- .../header/breadcrumbs/dropdown/menu.tsx | 1 + .../file-list/header/breadcrumbs/index.tsx | 16 ++++----- .../data-source/online-drive/index.tsx | 35 +++++++++++-------- .../data-source/store/slices/online-drive.ts | 14 ++++---- .../documents/create-from-pipeline/hooks.ts | 20 +++++------ .../documents/create-from-pipeline/index.tsx | 14 ++++---- .../panel/test-run/preparation/hooks.ts | 4 +-- .../panel/test-run/preparation/index.tsx | 4 +-- .../data-source/hooks/use-before-run-form.ts | 4 +-- 11 files changed, 65 insertions(+), 60 deletions(-) diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source-options/index.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source-options/index.tsx index cb88aec1da..f99b0bcf32 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/data-source-options/index.tsx +++ b/web/app/components/datasets/documents/create-from-pipeline/data-source-options/index.tsx @@ -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 ( diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/index.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/index.tsx index 09ea38078c..144decada5 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/index.tsx +++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/index.tsx @@ -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(null) const fileListRef = useRef([]) - 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 &&
}
)} - {fileList.length > 0 && ( + {localFileList.length > 0 && (
- {fileList.map((fileItem, index) => { + {localFileList.map((fileItem, index) => { const isUploading = fileItem.progress >= 0 && fileItem.progress < 100 const isError = fileItem.progress === -2 return ( diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/dropdown/menu.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/dropdown/menu.tsx index faf8e09c12..b0d8e8d70b 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/dropdown/menu.tsx +++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/dropdown/menu.tsx @@ -17,6 +17,7 @@ const Menu = ({ {breadcrumbs.map((breadcrumb, index) => { return ( { - const { setFileList, setSelectedFileIds, setBreadcrumbs, setPrefix, setBucket } = dataSourceStore.getState() - setFileList([]) + const { setOnlineDriveFileList, setSelectedFileIds, setBreadcrumbs, setPrefix, setBucket } = dataSourceStore.getState() + setOnlineDriveFileList([]) setSelectedFileIds([]) setBucket('') setBreadcrumbs([]) @@ -54,26 +54,26 @@ const Breadcrumbs = ({ }, [dataSourceStore]) const handleClickBucketName = useCallback(() => { - const { setFileList, setSelectedFileIds, setBreadcrumbs, setPrefix } = dataSourceStore.getState() - setFileList([]) + const { setOnlineDriveFileList, setSelectedFileIds, setBreadcrumbs, setPrefix } = dataSourceStore.getState() + setOnlineDriveFileList([]) setSelectedFileIds([]) setBreadcrumbs([]) setPrefix([]) }, [dataSourceStore]) const handleBackToRoot = useCallback(() => { - const { setFileList, setSelectedFileIds, setBreadcrumbs, setPrefix } = dataSourceStore.getState() - setFileList([]) + const { setOnlineDriveFileList, setSelectedFileIds, setBreadcrumbs, setPrefix } = dataSourceStore.getState() + setOnlineDriveFileList([]) setSelectedFileIds([]) setBreadcrumbs([]) setPrefix([]) }, [dataSourceStore]) const handleClickBreadcrumb = useCallback((index: number) => { - const { breadcrumbs, prefix, setFileList, setSelectedFileIds, setBreadcrumbs, 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) diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/index.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/index.tsx index e048d87dc0..75656162df 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/index.tsx +++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/index.tsx @@ -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' @@ -38,7 +38,7 @@ const OnlineDrive = ({ keywords, bucket, selectedFileIds, - fileList, + onlineDriveFileList, currentCredentialId, } = useDataSourceStoreWithSelector(useShallow(state => ({ nextPageParameters: state.nextPageParameters, @@ -47,11 +47,12 @@ const OnlineDrive = ({ 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, @@ -63,8 +64,10 @@ const OnlineDrive = ({ : `/rag/pipelines/${pipelineId}/workflows/draft/datasource/nodes/${nodeId}/run` const getOnlineDriveFiles = useCallback(async () => { - const { nextPageParameters, prefix, bucket, fileList, currentCredentialId } = dataSourceStore.getState() + if (isLoadingRef.current) return + const { nextPageParameters, prefix, bucket, onlineDriveFileList, currentCredentialId } = dataSourceStore.getState() setIsLoading(true) + isLoadingRef.current = true ssePost( datasourceNodeRunURL, { @@ -81,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, breadcrumbs, bucket) - setFileList([...fileList, ...newFileList]) + setOnlineDriveFileList([...onlineDriveFileList, ...newFileList]) isTruncated.current = newIsTruncated currentNextPageParametersRef.current = newNextPageParameters setHasBucket(newHasBucket) setIsLoading(false) + isLoadingRef.current = false }, onDataSourceNodeError: (error: DataSourceNodeErrorResponse) => { Toast.notify({ @@ -100,6 +104,7 @@ const OnlineDrive = ({ message: error.error, }) setIsLoading(false) + isLoadingRef.current = false }, }, ) @@ -109,7 +114,7 @@ const OnlineDrive = ({ 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) } @@ -118,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() @@ -152,9 +157,9 @@ const OnlineDrive = ({ }, [dataSourceStore, isInPipeline]) const handleOpenFolder = useCallback((file: OnlineDriveFile) => { - const { breadcrumbs, setBreadcrumbs, 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) } @@ -189,14 +194,14 @@ const OnlineDrive = ({ credentials={dataSourceAuth?.result || []} /> 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 @@ -43,12 +43,12 @@ export const createOnlineDriveSlice: StateCreator = (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(() => ({ diff --git a/web/app/components/datasets/documents/create-from-pipeline/hooks.ts b/web/app/components/datasets/documents/create-from-pipeline/hooks.ts index fb24ce5925..45dcaa6111 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/hooks.ts +++ b/web/app/components/datasets/documents/create-from-pipeline/hooks.ts @@ -65,7 +65,7 @@ export const useDatasourceOptions = (pipelineNodes: Node[]) 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, diff --git a/web/app/components/datasets/documents/create-from-pipeline/index.tsx b/web/app/components/datasets/documents/create-from-pipeline/index.tsx index b679051cf3..c9bb641287 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/index.tsx +++ b/web/app/components/datasets/documents/create-from-pipeline/index.tsx @@ -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 = () => {
file.file)} + localFiles={localFileList.map(file => file.file)} onlineDocuments={onlineDocuments} websitePages={websitePages} onlineDriveFiles={selectedOnlineDriveFileList} diff --git a/web/app/components/rag-pipeline/components/panel/test-run/preparation/hooks.ts b/web/app/components/rag-pipeline/components/panel/test-run/preparation/hooks.ts index 64f05c0cd5..3f2f49f455 100644 --- a/web/app/components/rag-pipeline/components/panel/test-run/preparation/hooks.ts +++ b/web/app/components/rag-pipeline/components/panel/test-run/preparation/hooks.ts @@ -110,13 +110,13 @@ export const useOnlineDrive = () => { const clearOnlineDriveData = useCallback(() => { const { - setFileList, + setOnlineDriveFileList, setBucket, setPrefix, setKeywords, setSelectedFileIds, } = dataSourceStore.getState() - setFileList([]) + setOnlineDriveFileList([]) setBucket('') setPrefix([]) setKeywords('') diff --git a/web/app/components/rag-pipeline/components/panel/test-run/preparation/index.tsx b/web/app/components/rag-pipeline/components/panel/test-run/preparation/index.tsx index b4dc32c122..0f869c2621 100644 --- a/web/app/components/rag-pipeline/components/panel/test-run/preparation/index.tsx +++ b/web/app/components/rag-pipeline/components/panel/test-run/preparation/index.tsx @@ -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, diff --git a/web/app/components/workflow/nodes/data-source/hooks/use-before-run-form.ts b/web/app/components/workflow/nodes/data-source/hooks/use-before-run-form.ts index 36540d6217..7b0a225e45 100644 --- a/web/app/components/workflow/nodes/data-source/hooks/use-before-run-form.ts +++ b/web/app/components/workflow/nodes/data-source/hooks/use-before-run-form.ts @@ -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, From 9a13cb5bdf523376eb443ca3a8b473c3343e03f7 Mon Sep 17 00:00:00 2001 From: twwu Date: Thu, 28 Aug 2025 13:58:03 +0800 Subject: [PATCH 3/6] refactor: remove unused state management in usePipelineRun hook --- web/app/components/rag-pipeline/hooks/use-pipeline-run.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/web/app/components/rag-pipeline/hooks/use-pipeline-run.ts b/web/app/components/rag-pipeline/hooks/use-pipeline-run.ts index 11031b0a56..4ed8cb95c7 100644 --- a/web/app/components/rag-pipeline/hooks/use-pipeline-run.ts +++ b/web/app/components/rag-pipeline/hooks/use-pipeline-run.ts @@ -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) => { From 740f1c5f2cfce573de088b1e2497e3af77a3f4f7 Mon Sep 17 00:00:00 2001 From: Joel Date: Thu, 28 Aug 2025 14:06:20 +0800 Subject: [PATCH 4/6] fix: tools value not update caused data outdated --- .../workflow/hooks/use-workflow-variables.ts | 18 +++++++++++------- .../nodes/_base/components/variable/utils.ts | 6 ++++-- .../variable/var-reference-picker.tsx | 1 + 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/web/app/components/workflow/hooks/use-workflow-variables.ts b/web/app/components/workflow/hooks/use-workflow-variables.ts index d5eebfde77..b42a41bab5 100644 --- a/web/app/components/workflow/hooks/use-workflow-variables.ts +++ b/web/app/components/workflow/hooks/use-workflow-variables.ts @@ -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, diff --git a/web/app/components/workflow/nodes/_base/components/variable/utils.ts b/web/app/components/workflow/nodes/_base/components/variable/utils.ts index 52e18ef10e..1df833d95f 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/utils.ts +++ b/web/app/components/workflow/nodes/_base/components/variable/utils.ts @@ -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 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) diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx index b90fd53125..e493b7b6b9 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx @@ -288,6 +288,7 @@ const VarReferencePicker: FC = ({ availableNodes, isChatMode, isConstant: !!isConstant, + preferSchemaType, }) const { isEnv, isChatVar, isRagVar, isValidVar, isException } = useMemo(() => { From e955a603c64ca162d9e8652297da9f2e81d1794a Mon Sep 17 00:00:00 2001 From: Joel Date: Thu, 28 Aug 2025 14:19:07 +0800 Subject: [PATCH 5/6] fix: can choose file in add in variable aggregator --- .../workflow/nodes/_base/components/add-variable-popup.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/web/app/components/workflow/nodes/_base/components/add-variable-popup.tsx b/web/app/components/workflow/nodes/_base/components/add-variable-popup.tsx index a7a3a89676..663ed074e8 100644 --- a/web/app/components/workflow/nodes/_base/components/add-variable-popup.tsx +++ b/web/app/components/workflow/nodes/_base/components/add-variable-popup.tsx @@ -27,6 +27,7 @@ export const AddVariablePopup = ({ hideSearch vars={availableVars} onChange={onSelect} + isSupportFileVar />
From edd41a30eb930fa1646880fe1b8a8e0bf054650f Mon Sep 17 00:00:00 2001 From: twwu Date: Thu, 28 Aug 2025 15:31:30 +0800 Subject: [PATCH 6/6] feat: add AddChunks icon and related components for knowledge base chunk structure --- .../assets/vender/knowledge/add-chunks.svg | 8 ++ .../icons/src/vender/knowledge/AddChunks.json | 71 ++++++++++++ .../icons/src/vender/knowledge/AddChunks.tsx | 20 ++++ .../base/icons/src/vender/knowledge/index.ts | 1 + .../detail/completed/common/empty.tsx | 16 +-- .../components/chunk-structure/index.tsx | 32 +++--- .../chunk-structure/instruction/index.tsx | 47 ++++++++ .../chunk-structure/instruction/line.tsx | 41 +++++++ .../workflow/nodes/knowledge-base/panel.tsx | 107 +++++++++--------- web/i18n/en-US/workflow.ts | 5 + web/i18n/zh-Hans/workflow.ts | 5 + 11 files changed, 278 insertions(+), 75 deletions(-) create mode 100644 web/app/components/base/icons/assets/vender/knowledge/add-chunks.svg create mode 100644 web/app/components/base/icons/src/vender/knowledge/AddChunks.json create mode 100644 web/app/components/base/icons/src/vender/knowledge/AddChunks.tsx create mode 100644 web/app/components/workflow/nodes/knowledge-base/components/chunk-structure/instruction/index.tsx create mode 100644 web/app/components/workflow/nodes/knowledge-base/components/chunk-structure/instruction/line.tsx diff --git a/web/app/components/base/icons/assets/vender/knowledge/add-chunks.svg b/web/app/components/base/icons/assets/vender/knowledge/add-chunks.svg new file mode 100644 index 0000000000..378baf3658 --- /dev/null +++ b/web/app/components/base/icons/assets/vender/knowledge/add-chunks.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/web/app/components/base/icons/src/vender/knowledge/AddChunks.json b/web/app/components/base/icons/src/vender/knowledge/AddChunks.json new file mode 100644 index 0000000000..51e1b17fb4 --- /dev/null +++ b/web/app/components/base/icons/src/vender/knowledge/AddChunks.json @@ -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" +} diff --git a/web/app/components/base/icons/src/vender/knowledge/AddChunks.tsx b/web/app/components/base/icons/src/vender/knowledge/AddChunks.tsx new file mode 100644 index 0000000000..fc1270ae66 --- /dev/null +++ b/web/app/components/base/icons/src/vender/knowledge/AddChunks.tsx @@ -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 & { + ref?: React.RefObject>; + }, +) => + +Icon.displayName = 'AddChunks' + +export default Icon diff --git a/web/app/components/base/icons/src/vender/knowledge/index.ts b/web/app/components/base/icons/src/vender/knowledge/index.ts index 1ad91ea8af..74e5a5fce8 100644 --- a/web/app/components/base/icons/src/vender/knowledge/index.ts +++ b/web/app/components/base/icons/src/vender/knowledge/index.ts @@ -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' diff --git a/web/app/components/datasets/documents/detail/completed/common/empty.tsx b/web/app/components/datasets/documents/detail/completed/common/empty.tsx index eef2aa9e25..93813cfa22 100644 --- a/web/app/components/datasets/documents/detail/completed/common/empty.tsx +++ b/web/app/components/datasets/documents/detail/completed/common/empty.tsx @@ -22,13 +22,13 @@ const Line = React.memo(({ className, }: LineProps) => { return ( - - + + - - - - + + + + @@ -47,8 +47,8 @@ const Empty: FC = ({
- - + +
diff --git a/web/app/components/workflow/nodes/knowledge-base/components/chunk-structure/index.tsx b/web/app/components/workflow/nodes/knowledge-base/components/chunk-structure/index.tsx index 92e72c7753..6410ab706f 100644 --- a/web/app/components/workflow/nodes/knowledge-base/components/chunk-structure/index.tsx +++ b/web/app/components/workflow/nodes/knowledge-base/components/chunk-structure/index.tsx @@ -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 && ( - - - {t('workflow.nodes.knowledgeBase.chooseChunkStructure')} - - )} - /> + <> + + + {t('workflow.nodes.knowledgeBase.chooseChunkStructure')} + + )} + /> + + ) } diff --git a/web/app/components/workflow/nodes/knowledge-base/components/chunk-structure/instruction/index.tsx b/web/app/components/workflow/nodes/knowledge-base/components/chunk-structure/instruction/index.tsx new file mode 100644 index 0000000000..596f7993c0 --- /dev/null +++ b/web/app/components/workflow/nodes/knowledge-base/components/chunk-structure/instruction/index.tsx @@ -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 ( +
+
+ + + + + +
+
+
+ {t('workflow.nodes.knowledgeBase.chunkStructureTip.title')} +
+
+

{t('workflow.nodes.knowledgeBase.chunkStructureTip.message')}

+ + {t('workflow.nodes.knowledgeBase.chunkStructureTip.learnMore')} + +
+
+
+ ) +} + +export default React.memo(Instruction) diff --git a/web/app/components/workflow/nodes/knowledge-base/components/chunk-structure/instruction/line.tsx b/web/app/components/workflow/nodes/knowledge-base/components/chunk-structure/instruction/line.tsx new file mode 100644 index 0000000000..1177130d2b --- /dev/null +++ b/web/app/components/workflow/nodes/knowledge-base/components/chunk-structure/instruction/line.tsx @@ -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 ( + + + + + + + + + + + ) + } + + return ( + + + + + + + + + + + ) +} + +export default React.memo(Line) diff --git a/web/app/components/workflow/nodes/knowledge-base/panel.tsx b/web/app/components/workflow/nodes/knowledge-base/panel.tsx index c076493f81..c3dd15ed42 100644 --- a/web/app/components/workflow/nodes/knowledge-base/panel.tsx +++ b/web/app/components/workflow/nodes/knowledge-base/panel.tsx @@ -47,7 +47,7 @@ const Panel: FC> = ({ } = 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> = ({ return variable.schemaType === 'parent_child_structure' case ChunkStructureEnum.question_answer: return variable.schemaType === 'qa_structure' + default: + return false } - return false }, [data.chunk_structure]) return (
- - - > = ({ readonly={nodesReadOnly} /> - -
- { - data.chunk_structure && ( - <> + { + data.chunk_structure && ( + <> + + + + +
> = ({
- - ) - } - -
-
+ +
+
+ + ) + }
) } diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index c21f0dc1b2..3585d7535b 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -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', diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index 498966537b..189331f44b 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -933,6 +933,11 @@ const translation = { knowledgeBase: { chunkStructure: '分段结构', chooseChunkStructure: '选择分段结构', + chunkStructureTip: { + title: '请选择分段结构', + message: '配置完成分段结构后,将自动加载剩余配置。', + learnMore: '了解更多', + }, changeChunkStructure: '更改分段结构', aboutRetrieval: '关于知识检索。', chunkIsRequired: '分段结构是必需的',