diff --git a/web/app/components/base/icons/assets/vender/knowledge/search-menu.svg b/web/app/components/base/icons/assets/vender/knowledge/search-menu.svg new file mode 100644 index 0000000000..39a2298c0e --- /dev/null +++ b/web/app/components/base/icons/assets/vender/knowledge/search-menu.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/web/app/components/base/icons/src/vender/knowledge/SearchMenu.json b/web/app/components/base/icons/src/vender/knowledge/SearchMenu.json new file mode 100644 index 0000000000..81853c0f01 --- /dev/null +++ b/web/app/components/base/icons/src/vender/knowledge/SearchMenu.json @@ -0,0 +1,77 @@ +{ + "icon": { + "type": "element", + "isRootNode": true, + "name": "svg", + "attributes": { + "width": "32", + "height": "33", + "viewBox": "0 0 32 33", + "fill": "none", + "xmlns": "http://www.w3.org/2000/svg" + }, + "children": [ + { + "type": "element", + "name": "path", + "attributes": { + "d": "M28.0049 16.5C28.0049 20.9183 24.4231 24.5 20.0049 24.5C15.5866 24.5 12.0049 20.9183 12.0049 16.5C12.0049 12.0817 15.5866 8.5 20.0049 8.5C24.4231 8.5 28.0049 12.0817 28.0049 16.5Z", + "stroke": "currentColor", + "stroke-width": "2", + "stroke-linecap": "round", + "stroke-linejoin": "round" + }, + "children": [] + }, + { + "type": "element", + "name": "path", + "attributes": { + "d": "M4.00488 16.5H6.67155", + "stroke": "currentColor", + "stroke-width": "2", + "stroke-linecap": "round", + "stroke-linejoin": "round" + }, + "children": [] + }, + { + "type": "element", + "name": "path", + "attributes": { + "d": "M4.00488 9.83301H8.00488", + "stroke": "currentColor", + "stroke-width": "2", + "stroke-linecap": "round", + "stroke-linejoin": "round" + }, + "children": [] + }, + { + "type": "element", + "name": "path", + "attributes": { + "d": "M4.00488 23.167H8.00488", + "stroke": "currentColor", + "stroke-width": "2", + "stroke-linecap": "round", + "stroke-linejoin": "round" + }, + "children": [] + }, + { + "type": "element", + "name": "path", + "attributes": { + "d": "M26 22.5L29.3333 25.8333", + "stroke": "currentColor", + "stroke-width": "2", + "stroke-linecap": "round", + "stroke-linejoin": "round" + }, + "children": [] + } + ] + }, + "name": "SearchMenu" +} \ No newline at end of file diff --git a/web/app/components/base/icons/src/vender/knowledge/SearchMenu.tsx b/web/app/components/base/icons/src/vender/knowledge/SearchMenu.tsx new file mode 100644 index 0000000000..4826abb20f --- /dev/null +++ b/web/app/components/base/icons/src/vender/knowledge/SearchMenu.tsx @@ -0,0 +1,20 @@ +// GENERATE BY script +// DON NOT EDIT IT MANUALLY + +import * as React from 'react' +import data from './SearchMenu.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 = 'SearchMenu' + +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 f894defd5f..1ad91ea8af 100644 --- a/web/app/components/base/icons/src/vender/knowledge/index.ts +++ b/web/app/components/base/icons/src/vender/knowledge/index.ts @@ -9,4 +9,5 @@ export { default as HighQuality } from './HighQuality' export { default as HybridSearch } from './HybridSearch' export { default as ParentChildChunk } from './ParentChildChunk' export { default as QuestionAndAnswer } from './QuestionAndAnswer' +export { default as SearchMenu } from './SearchMenu' export { default as VectorSearch } from './VectorSearch' diff --git a/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/header/breadcrumbs.tsx b/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/header/breadcrumbs.tsx index 56a595f8fb..47df7316f8 100644 --- a/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/header/breadcrumbs.tsx +++ b/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/header/breadcrumbs.tsx @@ -4,14 +4,12 @@ import { useTranslation } from 'react-i18next' type BreadcrumbsProps = { prefix: string[] keywords: string - resetKeywords: () => void searchResultsLength: number } const Breadcrumbs = ({ prefix, keywords, - resetKeywords, searchResultsLength, }: BreadcrumbsProps) => { const { t } = useTranslation() diff --git a/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/header/index.tsx b/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/header/index.tsx index 82feaa1c75..e0929a6ae6 100644 --- a/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/header/index.tsx +++ b/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/header/index.tsx @@ -1,51 +1,32 @@ -import React, { useState } from 'react' +import React from 'react' import Breadcrumbs from './breadcrumbs' import Input from '@/app/components/base/input' -import { useDebounceFn } from 'ahooks' import { useTranslation } from 'react-i18next' type HeaderProps = { prefix: string[] + inputValue: string keywords: string - resetKeywords: () => void - updateKeywords: (keywords: string) => void searchResultsLength: number + handleInputChange: React.ChangeEventHandler + handleResetKeywords: () => void } const Header = ({ prefix, + inputValue, keywords, - resetKeywords, - updateKeywords, searchResultsLength, + handleInputChange, + handleResetKeywords, }: HeaderProps) => { const { t } = useTranslation() - const [inputValue, setInputValue] = useState(keywords) - - const { run: updateKeywordsWithDebounce } = useDebounceFn( - (keywords: string) => { - updateKeywords(keywords) - }, - { wait: 500 }, - ) - - const handleInputChange = (e: React.ChangeEvent) => { - const keywords = e.target.value - setInputValue(keywords) - updateKeywordsWithDebounce(keywords) - } - - const handleResetKeywords = () => { - setInputValue('') - resetKeywords() - } return (
{ + const [inputValue, setInputValue] = useState(keywords) + + const { run: updateKeywordsWithDebounce } = useDebounceFn( + (keywords: string) => { + updateKeywords(keywords) + }, + { wait: 500 }, + ) + + const handleInputChange = (e: React.ChangeEvent) => { + const keywords = e.target.value + setInputValue(keywords) + updateKeywordsWithDebounce(keywords) + } + + const handleResetKeywords = () => { + setInputValue('') + resetKeywords() + } + return (
) diff --git a/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/list/empty-folder.tsx b/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/list/empty-folder.tsx new file mode 100644 index 0000000000..18dc63aee1 --- /dev/null +++ b/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/list/empty-folder.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import { useTranslation } from 'react-i18next' + +const EmptyFolder = () => { + const { t } = useTranslation() + + return ( +
+ {t('datasetPipeline.onlineDrive.emptyFolder')} +
+ ) +} + +export default React.memo(EmptyFolder) diff --git a/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/list/empty-search-result.tsx b/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/list/empty-search-result.tsx new file mode 100644 index 0000000000..77c85d624c --- /dev/null +++ b/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/list/empty-search-result.tsx @@ -0,0 +1,35 @@ +import Button from '@/app/components/base/button' +import { SearchMenu } from '@/app/components/base/icons/src/vender/knowledge' +import React from 'react' +import { useTranslation } from 'react-i18next' + +type EmptySearchResultProps = { + onResetKeywords: () => void +} + +const EmptySearchResult = ({ + onResetKeywords, +}: EmptySearchResultProps & { + className?: string +}) => { + const { t } = useTranslation() + + return ( +
+ +
+ {t('datasetPipeline.onlineDrive.emptySearchResult')} +
+ +
+ ) +} + +export default React.memo(EmptySearchResult) diff --git a/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/list/index.tsx b/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/list/index.tsx index f6eaafcc80..3968e673e1 100644 --- a/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/list/index.tsx +++ b/web/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive/file-list/list/index.tsx @@ -1,33 +1,55 @@ import type { OnlineDriveFile } from '@/models/pipeline' import Item from './item' +import EmptyFolder from './empty-folder' +import EmptySearchResult from './empty-search-result' type FileListProps = { fileList: OnlineDriveFile[] selectedFileList: string[] + keywords: string + handleResetKeywords: () => void } const List = ({ fileList, selectedFileList, + keywords, + handleResetKeywords, }: FileListProps) => { + const isEmptyFolder = fileList.length === 0 && keywords.length === 0 + const isSearchResultEmpty = fileList.length === 0 && keywords.length > 0 + return ( -
-
- { - fileList.map((file) => { - const isSelected = selectedFileList.includes(file.key) - return ( - { console.log(file) }} - onOpen={(file) => { console.log(file) }} - /> - ) - }) - } -
+
+ { + isEmptyFolder && ( + + ) + } + { + isSearchResultEmpty && ( + + ) + } + {fileList.length > 0 && ( +
+ { + fileList.map((file) => { + const isSelected = selectedFileList.includes(file.key) + return ( + { console.log(file) }} + onOpen={(file) => { console.log(file) }} + disabled + /> + ) + }) + } +
+ )}
) } diff --git a/web/i18n/en-US/dataset-pipeline.ts b/web/i18n/en-US/dataset-pipeline.ts index c01af0a625..5a55bdeec1 100644 --- a/web/i18n/en-US/dataset-pipeline.ts +++ b/web/i18n/en-US/dataset-pipeline.ts @@ -115,11 +115,12 @@ const translation = { breadcrumbs: { allBuckets: 'All Cloud Storage Buckets', searchResult: 'Find {{searchResultsLength}} items in "{{folderName}}" folder', - noSearchResult: 'No items were found', - resetKeywords: 'Reset keywords', searchPlaceholder: 'Search files...', }, notSupportedFileType: 'This file type is not supported', + emptyFolder: 'This folder is empty', + emptySearchResult: 'No items were found', + resetKeywords: 'Reset keywords', }, } diff --git a/web/i18n/zh-Hans/dataset-pipeline.ts b/web/i18n/zh-Hans/dataset-pipeline.ts index 682ea34940..053780d222 100644 --- a/web/i18n/zh-Hans/dataset-pipeline.ts +++ b/web/i18n/zh-Hans/dataset-pipeline.ts @@ -115,11 +115,12 @@ const translation = { breadcrumbs: { allBuckets: '所有云存储桶', searchResult: '在 "{{folderName}}" 文件夹中找到 {{searchResultsLength}} 个项目', - noSearchResult: '未找到项目', - resetKeywords: '重置关键词', searchPlaceholder: '搜索文件...', }, notSupportedFileType: '不支持此文件类型', + emptyFolder: '此文件夹为空', + emptySearchResult: '未找到任何项目', + resetKeywords: '重置关键词', }, }