- {t('common.noData')}
+
+ {text ||
+ (type === 'data' ? t('common.noData') : t('common.noResults'))}
)}
{children}
@@ -95,3 +50,65 @@ const Empty = (props: EmptyProps) => {
};
export default Empty;
+
+export const EmptyCard = (props: EmptyCardProps) => {
+ const { icon, className, children, title, description, style } = props;
+ return (
+
+ {icon}
+ {title &&
{title}
}
+ {description && (
+
{description}
+ )}
+ {children}
+
+ );
+};
+
+export const EmptyAppCard = (props: {
+ type: EmptyCardType;
+ onClick?: () => void;
+ showIcon?: boolean;
+ className?: string;
+ size?: 'small' | 'large';
+}) => {
+ const { type, showIcon, className } = props;
+ let defaultClass = '';
+ let style = {};
+ switch (props.size) {
+ case 'small':
+ style = { width: '256px' };
+ defaultClass = 'mt-1';
+ break;
+ case 'large':
+ style = { width: '480px' };
+ defaultClass = 'mt-5';
+ break;
+ default:
+ defaultClass = '';
+ break;
+ }
+ return (
+
+ );
+};
diff --git a/web/src/components/empty/interface.ts b/web/src/components/empty/interface.ts
new file mode 100644
index 000000000..73fef1d60
--- /dev/null
+++ b/web/src/components/empty/interface.ts
@@ -0,0 +1,18 @@
+import { EmptyType } from './constant';
+
+export type EmptyProps = {
+ className?: string;
+ children?: React.ReactNode;
+ type?: EmptyType;
+ text?: string;
+ iconWidth?: number;
+};
+
+export type EmptyCardProps = {
+ icon?: React.ReactNode;
+ className?: string;
+ children?: React.ReactNode;
+ title?: string;
+ description?: string;
+ style?: React.CSSProperties;
+};
diff --git a/web/src/hooks/llm-hooks.tsx b/web/src/hooks/llm-hooks.tsx
index d3e38427c..fb83d2974 100644
--- a/web/src/hooks/llm-hooks.tsx
+++ b/web/src/hooks/llm-hooks.tsx
@@ -58,7 +58,7 @@ export const useSelectLlmOptions = () => {
function buildLlmOptionsWithIcon(x: IThirdOAIModel) {
return {
label: (
-
+
{
const [searchParams] = useSearchParams();
const { id } = useParams();
- const navigateToDatasetList = useCallback(() => {
- navigate(Routes.Datasets);
- }, [navigate]);
+ const navigateToDatasetList = useCallback(
+ ({ isCreate = false }: { isCreate?: boolean }) => {
+ if (isCreate) {
+ navigate(Routes.Datasets + '?isCreate=true');
+ } else {
+ navigate(Routes.Datasets);
+ }
+ },
+ [navigate],
+ );
const navigateToDataset = useCallback(
(id: string) => () => {
diff --git a/web/src/hooks/user-setting-hooks.tsx b/web/src/hooks/user-setting-hooks.tsx
index bc4e177db..c43f5005b 100644
--- a/web/src/hooks/user-setting-hooks.tsx
+++ b/web/src/hooks/user-setting-hooks.tsx
@@ -54,7 +54,7 @@ export const useFetchTenantInfo = (
): ResponseGetType => {
const { t } = useTranslation();
const { data, isFetching: loading } = useQuery({
- queryKey: ['tenantInfo'],
+ queryKey: ['tenantInfo', showEmptyModelWarn],
initialData: {},
gcTime: 0,
queryFn: async () => {
@@ -99,7 +99,6 @@ export const useSelectParserList = (): Array<{
label: string;
}> => {
const { data: tenantInfo } = useFetchTenantInfo(true);
-
const parserList = useMemo(() => {
const parserArray: Array = tenantInfo?.parser_ids?.split(',') ?? [];
return parserArray.map((x) => {
diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts
index 9a952a54c..b05c43b7d 100644
--- a/web/src/locales/en.ts
+++ b/web/src/locales/en.ts
@@ -3,7 +3,7 @@ export default {
common: {
confirm: 'Confirm',
back: 'Back',
- noResults: 'No results.',
+ noResults: 'No results found',
selectPlaceholder: 'select value',
selectAll: 'Select all',
delete: 'Delete',
@@ -51,7 +51,7 @@ export default {
remove: 'Remove',
search: 'Search',
noDataFound: 'No data found.',
- noData: 'No data',
+ noData: 'No data available',
promptPlaceholder: `Please input or use / to quickly insert variables.`,
mcp: {
namePlaceholder: 'My MCP Server',
@@ -2026,6 +2026,7 @@ Important structured information may include: names, dates, locations, events, k
processingSuccessTip: 'Total successfully processed files',
processingFailedTip: 'Total failed processes',
processing: 'Processing',
+ noData: 'No log yet',
},
deleteModal: {
@@ -2039,6 +2040,15 @@ Important structured information may include: names, dates, locations, events, k
delMember: 'Delete member',
},
+ empty: {
+ noMCP: 'No MCP servers available',
+ agentTitle: 'No agent app created yet',
+ datasetTitle: 'No dataset created yet',
+ chatTitle: 'No chat app created yet',
+ searchTitle: 'No search app created yet',
+ addNow: 'Add Now',
+ },
+
admin: {
loginTitle: 'Admin Console',
title: 'RAGFlow',
diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts
index da264db7a..7601cc3c4 100644
--- a/web/src/locales/zh.ts
+++ b/web/src/locales/zh.ts
@@ -3,7 +3,7 @@ export default {
common: {
confirm: '确定',
back: '返回',
- noResults: '无结果。',
+ noResults: '未查到结果',
selectPlaceholder: '请选择',
selectAll: '全选',
delete: '删除',
@@ -1878,6 +1878,27 @@ Tokenizer 会根据所选方式将内容存储为对应的数据结构。`,
downloadFailedTip: '下载失败总数',
processingSuccessTip: '处理成功的文件总数',
processingFailedTip: '处理失败的文件总数',
+ noData: '暂无日志',
+ },
+
+ deleteModal: {
+ delAgent: '删除智能体',
+ delDataset: '删除知识库',
+ delSearch: '删除搜索',
+ delFile: '删除文件',
+ delFiles: '删除文件',
+ delFilesContent: '已选择 {{count}} 个文件',
+ delChat: '删除聊天',
+ delMember: '删除成员',
+ },
+
+ empty: {
+ noMCP: '暂无 MCP 服务器可用',
+ agentTitle: '尚未创建智能体',
+ datasetTitle: '尚未创建数据集',
+ chatTitle: '尚未创建聊天应用',
+ searchTitle: '尚未创建搜索应用',
+ addNow: '立即添加',
},
deleteModal: {
diff --git a/web/src/pages/agents/index.tsx b/web/src/pages/agents/index.tsx
index b3858926c..3600d3bd6 100644
--- a/web/src/pages/agents/index.tsx
+++ b/web/src/pages/agents/index.tsx
@@ -1,4 +1,6 @@
import { CardContainer } from '@/components/card-container';
+import { EmptyCardType } from '@/components/empty/constant';
+import { EmptyAppCard } from '@/components/empty/empty';
import ListFilterBar from '@/components/list-filter-bar';
import { RenameDialog } from '@/components/rename-dialog';
import { Button } from '@/components/ui/button';
@@ -14,7 +16,8 @@ import { useFetchAgentListByPage } from '@/hooks/use-agent-request';
import { t } from 'i18next';
import { pick } from 'lodash';
import { Clipboard, ClipboardPlus, FileInput, Plus } from 'lucide-react';
-import { useCallback } from 'react';
+import { useCallback, useEffect } from 'react';
+import { useSearchParams } from 'umi';
import { AgentCard } from './agent-card';
import { CreateAgentDialog } from './create-agent-dialog';
import { useCreateAgentOrPipeline } from './hooks/use-create-agent';
@@ -67,95 +70,120 @@ export default function Agents() {
},
[setPagination],
);
-
+ const [searchUrl, setSearchUrl] = useSearchParams();
+ const isCreate = searchUrl.get('isCreate') === 'true';
+ useEffect(() => {
+ if (isCreate) {
+ showCreatingModal();
+ searchUrl.delete('isCreate');
+ setSearchUrl(searchUrl);
+ }
+ }, [isCreate, showCreatingModal, searchUrl, setSearchUrl]);
return (
-
-
-
-
-
-
-
-
-
-
- {t('flow.createFromBlank')}
-
-
-
- {t('flow.createFromTemplate')}
-
-
-
- {t('flow.importJsonFile')}
-
-
-
-
-
-
-
- {data.map((x) => {
- return (
-
- );
- })}
-
-
-
-
-
- {agentRenameVisible && (
-
+ <>
+ {(!data?.length || data?.length <= 0) && (
+
+ showCreatingModal()}
+ />
+
)}
- {creatingVisible && (
-
- )}
- {fileUploadVisible && (
-
- )}
-
+
+ {!!data?.length && (
+ <>
+
+
+
+
+
+
+
+
+
+ {t('flow.createFromBlank')}
+
+
+
+ {t('flow.createFromTemplate')}
+
+
+
+ {t('flow.importJsonFile')}
+
+
+
+
+
+
+
+ {data.map((x) => {
+ return (
+
+ );
+ })}
+
+
+
+
+
+ >
+ )}
+ {agentRenameVisible && (
+
+ )}
+ {creatingVisible && (
+
+ )}
+ {fileUploadVisible && (
+
+ )}
+
+ >
);
}
diff --git a/web/src/pages/dataset/dataset-overview/overview-table.tsx b/web/src/pages/dataset/dataset-overview/overview-table.tsx
index 26e89cd61..a0aa79702 100644
--- a/web/src/pages/dataset/dataset-overview/overview-table.tsx
+++ b/web/src/pages/dataset/dataset-overview/overview-table.tsx
@@ -1,3 +1,5 @@
+import { EmptyType } from '@/components/empty/constant';
+import Empty from '@/components/empty/empty';
import FileStatusBadge from '@/components/file-status-badge';
import { FileIcon, IconFontFill } from '@/components/icon-font';
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
@@ -344,6 +346,7 @@ const FileLogsTable: FC = ({
const [columnFilters, setColumnFilters] = useState([]);
const [rowSelection, setRowSelection] = useState({});
const { t } = useTranslate('knowledgeDetails');
+ const { t: tDatasetOverview } = useTranslate('datasetOverview');
const [isModalVisible, setIsModalVisible] = useState(false);
const { navigateToDataflowResult } = useNavigatePage();
const [logInfo, setLogInfo] = useState();
@@ -445,7 +448,10 @@ const FileLogsTable: FC = ({
) : (
- No results.
+
)}
diff --git a/web/src/pages/dataset/dataset/dataset-table.tsx b/web/src/pages/dataset/dataset/dataset-table.tsx
index cdbeaa3d3..a49d40ddc 100644
--- a/web/src/pages/dataset/dataset/dataset-table.tsx
+++ b/web/src/pages/dataset/dataset/dataset-table.tsx
@@ -14,6 +14,8 @@ import {
import * as React from 'react';
import { ChunkMethodDialog } from '@/components/chunk-method-dialog';
+import { EmptyType } from '@/components/empty/constant';
+import Empty from '@/components/empty/empty';
import { RenameDialog } from '@/components/rename-dialog';
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
import {
@@ -164,7 +166,7 @@ export function DatasetTable({
) : (
- No results.
+
)}
diff --git a/web/src/pages/dataset/dataset/use-dataset-table-columns.tsx b/web/src/pages/dataset/dataset/use-dataset-table-columns.tsx
index 3259cbe74..845c9e76a 100644
--- a/web/src/pages/dataset/dataset/use-dataset-table-columns.tsx
+++ b/web/src/pages/dataset/dataset/use-dataset-table-columns.tsx
@@ -136,7 +136,7 @@ export function useDatasetTableColumns({
{
DataSourceInfo[
row.original.source_type as keyof typeof DataSourceInfo
- ].icon
+ ]?.icon
}
)}
diff --git a/web/src/pages/dataset/testing/testing-result.tsx b/web/src/pages/dataset/testing/testing-result.tsx
index 3c913ed33..853120cf5 100644
--- a/web/src/pages/dataset/testing/testing-result.tsx
+++ b/web/src/pages/dataset/testing/testing-result.tsx
@@ -1,3 +1,4 @@
+import { EmptyType } from '@/components/empty/constant';
import Empty from '@/components/empty/empty';
import { FormContainer } from '@/components/form-container';
import { FilterButton } from '@/components/list-filter-bar';
@@ -101,7 +102,7 @@ export function TestingResult({
{!data.chunks?.length && !loading && (
-
+
{data.isRuned && (
{t('knowledgeDetails.noTestResultsForRuned')}
diff --git a/web/src/pages/datasets/index.tsx b/web/src/pages/datasets/index.tsx
index 865c2dca0..c0515fc99 100644
--- a/web/src/pages/datasets/index.tsx
+++ b/web/src/pages/datasets/index.tsx
@@ -1,13 +1,17 @@
import { CardContainer } from '@/components/card-container';
+import { EmptyCardType } from '@/components/empty/constant';
+import { EmptyAppCard } from '@/components/empty/empty';
import ListFilterBar from '@/components/list-filter-bar';
import { RenameDialog } from '@/components/rename-dialog';
import { Button } from '@/components/ui/button';
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
import { useFetchNextKnowledgeListByPage } from '@/hooks/use-knowledge-request';
+import { useQueryClient } from '@tanstack/react-query';
import { pick } from 'lodash';
import { Plus } from 'lucide-react';
-import { useCallback } from 'react';
+import { useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
+import { useSearchParams } from 'umi';
import { DatasetCard } from './dataset-card';
import { DatasetCreatingDialog } from './dataset-creating-dialog';
import { useSaveKnowledge } from './hooks';
@@ -52,59 +56,86 @@ export default function Datasets() {
},
[setPagination],
);
-
+ const [searchUrl, setSearchUrl] = useSearchParams();
+ const isCreate = searchUrl.get('isCreate') === 'true';
+ const queryClient = useQueryClient();
+ useEffect(() => {
+ if (isCreate) {
+ queryClient.invalidateQueries({ queryKey: ['tenantInfo'] });
+ showModal();
+ searchUrl.delete('isCreate');
+ setSearchUrl(searchUrl);
+ }
+ }, [isCreate, showModal, searchUrl, setSearchUrl]);
return (
-
-
-
-
-
-
- {kbs.map((dataset) => {
- return (
-
- );
- })}
-
-
-
-
-
- {visible && (
-
- )}
- {datasetRenameVisible && (
-
- )}
-
+ <>
+
+ {(!kbs?.length || kbs?.length <= 0) && (
+
+ showModal()}
+ />
+
+ )}
+ {!!kbs?.length && (
+ <>
+
+
+
+
+
+ {kbs.map((dataset) => {
+ return (
+
+ );
+ })}
+
+
+
+
+
+ >
+ )}
+ {visible && (
+
+ )}
+ {datasetRenameVisible && (
+
+ )}
+
+ >
);
}
diff --git a/web/src/pages/home/agent-list.tsx b/web/src/pages/home/agent-list.tsx
index 5b74c3db0..7c0e60128 100644
--- a/web/src/pages/home/agent-list.tsx
+++ b/web/src/pages/home/agent-list.tsx
@@ -3,11 +3,18 @@ import { MoreButton } from '@/components/more-button';
import { RenameDialog } from '@/components/rename-dialog';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { useFetchAgentListByPage } from '@/hooks/use-agent-request';
+import { useEffect } from 'react';
import { AgentDropdown } from '../agents/agent-dropdown';
import { useRenameAgent } from '../agents/use-rename-agent';
-export function Agents() {
- const { data } = useFetchAgentListByPage();
+export function Agents({
+ setListLength,
+ setLoading,
+}: {
+ setListLength: (length: number) => void;
+ setLoading?: (loading: boolean) => void;
+}) {
+ const { data, loading } = useFetchAgentListByPage();
const { navigateToAgent } = useNavigatePage();
const {
agentRenameLoading,
@@ -18,6 +25,11 @@ export function Agents() {
showAgentRenameModal,
} = useRenameAgent();
+ useEffect(() => {
+ setListLength(data?.length || 0);
+ setLoading?.(loading || false);
+ }, [data, setListLength, loading, setLoading]);
+
return (
<>
{data.slice(0, 10).map((x) => (
diff --git a/web/src/pages/home/applications.tsx b/web/src/pages/home/applications.tsx
index 4c07f160e..5686fc04f 100644
--- a/web/src/pages/home/applications.tsx
+++ b/web/src/pages/home/applications.tsx
@@ -1,4 +1,6 @@
import { CardSineLineContainer } from '@/components/card-singleline-container';
+import { EmptyCardType } from '@/components/empty/constant';
+import { EmptyAppCard } from '@/components/empty/empty';
import { HomeIcon } from '@/components/svg-icon';
import { Segmented, SegmentedValue } from '@/components/ui/segmented';
import { Routes } from '@/routes';
@@ -16,14 +18,29 @@ const IconMap = {
[Routes.Agents]: 'agents',
};
+const EmptyTypeMap = {
+ [Routes.Chats]: EmptyCardType.Chat,
+ [Routes.Searches]: EmptyCardType.Search,
+ [Routes.Agents]: EmptyCardType.Agent,
+};
+
export function Applications() {
const [val, setVal] = useState(Routes.Chats);
const { t } = useTranslation();
const navigate = useNavigate();
+ const [listLength, setListLength] = useState(0);
+ const [loading, setLoading] = useState(false);
- const handleNavigate = useCallback(() => {
- navigate(val);
- }, [navigate, val]);
+ const handleNavigate = useCallback(
+ ({ isCreate }: { isCreate?: boolean }) => {
+ if (isCreate) {
+ navigate(val + '?isCreate=true');
+ } else {
+ navigate(val);
+ }
+ },
+ [navigate, val],
+ );
const options = useMemo(
() => [
@@ -36,16 +53,14 @@ export function Applications() {
const handleChange = (path: SegmentedValue) => {
setVal(path as Routes);
+ setListLength(0);
+ setLoading(true);
};
return (
- {/* */}
{/* */}
- {val === Routes.Agents && }
- {val === Routes.Chats && }
- {val === Routes.Searches && }
- {}
+ {val === Routes.Agents && (
+ setListLength(length)}
+ setLoading={(loading: boolean) => setLoading(loading)}
+ >
+ )}
+ {val === Routes.Chats && (
+ setListLength(length)}
+ setLoading={(loading: boolean) => setLoading(loading)}
+ >
+ )}
+ {val === Routes.Searches && (
+ setListLength(length)}
+ setLoading={(loading: boolean) => setLoading(loading)}
+ >
+ )}
+ {listLength > 0 && (
+ handleNavigate({ isCreate: false })}
+ >
+ )}
+ {listLength <= 0 && !loading && (
+
handleNavigate({ isCreate: true })}
+ />
+ )}
{/* */}
);
diff --git a/web/src/pages/home/chat-list.tsx b/web/src/pages/home/chat-list.tsx
index 6178f85d7..c53ea1708 100644
--- a/web/src/pages/home/chat-list.tsx
+++ b/web/src/pages/home/chat-list.tsx
@@ -3,13 +3,20 @@ import { MoreButton } from '@/components/more-button';
import { RenameDialog } from '@/components/rename-dialog';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { useFetchDialogList } from '@/hooks/use-chat-request';
+import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { ChatDropdown } from '../next-chats/chat-dropdown';
import { useRenameChat } from '../next-chats/hooks/use-rename-chat';
-export function ChatList() {
+export function ChatList({
+ setListLength,
+ setLoading,
+}: {
+ setListLength: (length: number) => void;
+ setLoading?: (loading: boolean) => void;
+}) {
const { t } = useTranslation();
- const { data } = useFetchDialogList();
+ const { data, loading } = useFetchDialogList();
const { navigateToChat } = useNavigatePage();
const {
@@ -20,7 +27,10 @@ export function ChatList() {
onChatRenameOk,
chatRenameLoading,
} = useRenameChat();
-
+ useEffect(() => {
+ setListLength(data?.dialogs?.length || 0);
+ setLoading?.(loading || false);
+ }, [data, setListLength, loading, setLoading]);
return (
<>
{data.dialogs.slice(0, 10).map((x) => (
diff --git a/web/src/pages/home/datasets.tsx b/web/src/pages/home/datasets.tsx
index 4d78d34d0..34c4b9267 100644
--- a/web/src/pages/home/datasets.tsx
+++ b/web/src/pages/home/datasets.tsx
@@ -1,4 +1,6 @@
import { CardSineLineContainer } from '@/components/card-singleline-container';
+import { EmptyCardType } from '@/components/empty/constant';
+import { EmptyAppCard } from '@/components/empty/empty';
import { RenameDialog } from '@/components/rename-dialog';
import { HomeIcon } from '@/components/svg-icon';
import { CardSkeleton } from '@/components/ui/skeleton';
@@ -35,18 +37,32 @@ export function Datasets() {
) : (
-
- {kbs
- ?.slice(0, 6)
- .map((dataset) => (
-
- ))}
- {}
-
+ <>
+ {kbs?.length > 0 && (
+
+ {kbs
+ ?.slice(0, 6)
+ .map((dataset) => (
+
+ ))}
+ {
+ navigateToDatasetList({ isCreate: false })}
+ >
+ }
+
+ )}
+ {kbs?.length <= 0 && (
+ navigateToDatasetList({ isCreate: true })}
+ />
+ )}
+ >
//
)}
diff --git a/web/src/pages/home/search-list.tsx b/web/src/pages/home/search-list.tsx
index 90cc098d3..9474a54a0 100644
--- a/web/src/pages/home/search-list.tsx
+++ b/web/src/pages/home/search-list.tsx
@@ -3,11 +3,18 @@ import { IconFont } from '@/components/icon-font';
import { MoreButton } from '@/components/more-button';
import { RenameDialog } from '@/components/rename-dialog';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
+import { useEffect } from 'react';
import { useFetchSearchList, useRenameSearch } from '../next-searches/hooks';
import { SearchDropdown } from '../next-searches/search-dropdown';
-export function SearchList() {
- const { data, refetch: refetchList } = useFetchSearchList();
+export function SearchList({
+ setListLength,
+ setLoading,
+}: {
+ setListLength: (length: number) => void;
+ setLoading?: (loading: boolean) => void;
+}) {
+ const { data, refetch: refetchList, isLoading } = useFetchSearchList();
const { navigateToSearch } = useNavigatePage();
const {
openCreateModal,
@@ -22,6 +29,11 @@ export function SearchList() {
refetchList();
});
};
+
+ useEffect(() => {
+ setListLength(data?.data?.search_apps?.length || 0);
+ setLoading?.(isLoading || false);
+ }, [data, setListLength, isLoading, setLoading]);
return (
<>
{data?.data.search_apps.slice(0, 10).map((x) => (
diff --git a/web/src/pages/next-chats/index.tsx b/web/src/pages/next-chats/index.tsx
index 4b54ee74b..e6667252f 100644
--- a/web/src/pages/next-chats/index.tsx
+++ b/web/src/pages/next-chats/index.tsx
@@ -1,4 +1,6 @@
import { CardContainer } from '@/components/card-container';
+import { EmptyCardType } from '@/components/empty/constant';
+import { EmptyAppCard } from '@/components/empty/empty';
import ListFilterBar from '@/components/list-filter-bar';
import { RenameDialog } from '@/components/rename-dialog';
import { Button } from '@/components/ui/button';
@@ -6,8 +8,9 @@ import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
import { useFetchDialogList } from '@/hooks/use-chat-request';
import { pick } from 'lodash';
import { Plus } from 'lucide-react';
-import { useCallback } from 'react';
+import { useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
+import { useSearchParams } from 'umi';
import { ChatCard } from './chat-card';
import { useRenameChat } from './hooks/use-rename-chat';
@@ -35,41 +38,66 @@ export default function ChatList() {
showChatRenameModal();
}, [showChatRenameModal]);
+ const [searchParams, setSearchParams] = useSearchParams();
+ const isCreate = searchParams.get('isCreate') === 'true';
+ useEffect(() => {
+ if (isCreate) {
+ handleShowCreateModal();
+ searchParams.delete('isCreate');
+ setSearchParams(searchParams);
+ }
+ }, [isCreate, handleShowCreateModal, searchParams, setSearchParams]);
+
return (
-
-
-
-
-
-
-
- {data.dialogs.map((x) => {
- return (
-
- );
- })}
-
-
-
-
-
+ {data.dialogs?.length <= 0 && (
+
+ handleShowCreateModal()}
+ />
+
+ )}
+ {data.dialogs?.length > 0 && (
+ <>
+
+
+
+
+
+
+
+ {data.dialogs.map((x) => {
+ return (
+
+ );
+ })}
+
+
+
+
+
+ >
+ )}
{chatRenameVisible && (
void;
}
const RetrievalDocuments = ({
onTesting,
selectedDocumentIds,
setSelectedDocumentIds,
+ setLoading,
}: IProps) => {
const { documents: documentsAll } = useAllTestingResult();
const { documents } = useSelectTestingResult();
+ const isTesting = useChunkIsTesting();
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+
+ useEffect(() => {
+ if (isTesting) {
+ setLoading?.(true);
+ } else {
+ setLoading?.(false);
+ }
+ }, [isTesting, setLoading]);
+
const { documents: useDocuments } = {
documents:
documentsAll?.length > documents?.length ? documentsAll : documents,
@@ -45,6 +58,9 @@ const RetrievalDocuments = ({
useState(selectedDocumentIds);
const multiOptions = useMemo(() => {
+ if (!useDocuments || !useDocuments.length) {
+ return [];
+ }
return useDocuments?.map((item) => {
return {
label: item.doc_name,
@@ -97,36 +113,38 @@ const RetrievalDocuments = ({
return (
-
+ {!isSearchStrEmpty &&
+ !retrievalLoading &&
+ !answer.answer &&
+ !sendingLoading &&
+ total <= 0 &&
+ chunks?.length <= 0 &&
+ relatedQuestions?.length <= 0 && (
+
+
+
+ )}
{total > 0 && (
diff --git a/web/src/pages/next-searches/index.tsx b/web/src/pages/next-searches/index.tsx
index b4e28152b..4267dbbe7 100644
--- a/web/src/pages/next-searches/index.tsx
+++ b/web/src/pages/next-searches/index.tsx
@@ -1,4 +1,6 @@
import { CardContainer } from '@/components/card-container';
+import { EmptyCardType } from '@/components/empty/constant';
+import { EmptyAppCard } from '@/components/empty/empty';
import { IconFont } from '@/components/icon-font';
import ListFilterBar from '@/components/list-filter-bar';
import { RenameDialog } from '@/components/rename-dialog';
@@ -6,6 +8,8 @@ import { Button } from '@/components/ui/button';
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
import { useTranslate } from '@/hooks/common-hooks';
import { Plus } from 'lucide-react';
+import { useCallback, useEffect } from 'react';
+import { useSearchParams } from 'umi';
import { useFetchSearchList, useRenameSearch } from './hooks';
import { SearchCard } from './search-card';
@@ -27,6 +31,7 @@ export default function SearchList() {
onSearchRenameOk,
initialSearchName,
} = useRenameSearch();
+
const handleSearchChange = (value: string) => {
console.log(value);
};
@@ -35,61 +40,86 @@ export default function SearchList() {
refetchList();
});
};
- const openCreateModalFun = () => {
+ const openCreateModalFun = useCallback(() => {
// setIsEdit(false);
showSearchRenameModal();
- };
+ }, [showSearchRenameModal]);
const handlePageChange = (page: number, pageSize: number) => {
// setIsEdit(false);
setSearchListParams({ ...searchParams, page, page_size: pageSize });
};
+ const [searchUrl, setSearchUrl] = useSearchParams();
+ const isCreate = searchUrl.get('isCreate') === 'true';
+ useEffect(() => {
+ if (isCreate) {
+ openCreateModalFun();
+ searchUrl.delete('isCreate');
+ setSearchUrl(searchUrl);
+ }
+ }, [isCreate, openCreateModalFun, searchUrl, setSearchUrl]);
+
return (
-
-
handleSearchChange(e.target.value)}
- >
- {
- openCreateModalFun();
- }}
- >
-
- {t('createSearch')}
-
-
-
-
-
- {list?.data.search_apps.map((x) => {
- return (
- {
- showSearchRenameModal(x);
- }}
- >
- );
- })}
-
-
- {list?.data.total && list?.data.total > 0 && (
-
-
+ openCreateModalFun()}
/>
)}
-
+ {!!list?.data?.search_apps?.length && (
+ <>
+
+
handleSearchChange(e.target.value)}
+ >
+ {
+ openCreateModalFun();
+ }}
+ >
+
+ {t('createSearch')}
+
+
+
+
+
+ {list?.data.search_apps.map((x) => {
+ return (
+ {
+ showSearchRenameModal(x);
+ }}
+ >
+ );
+ })}
+
+
+ {list?.data.total && list?.data.total > 0 && (
+
+
+
+ )}
+ >
+ )}
{openCreateModal && (
}
>
- {isSelectionMode && (
-
-
-
-
- {t('mcp.selected')} {selectedList.length}
-
-
-
-
- {t('mcp.export')}
-
-
- ),
- }}
- >
-
-
- {t('common.delete')}
-
-
-
-
+ {!data.mcp_servers?.length && (
+
+
{t('empty.noMCP')}
+
+ {t('empty.addNow')}
+
+
+ )}
+ {!!data.mcp_servers?.length && (
+ <>
+ {isSelectionMode && (
+
+
+
+
+ {t('mcp.selected')} {selectedList.length}
+
+
+
+
+ {t('mcp.export')}
+
+
+ ),
+ }}
+ >
+
+
+ {t('common.delete')}
+
+
+
+
+ )}
+
+ {data.mcp_servers.map((item) => (
+
+ ))}
+
+
+
+
+ >
)}
-
- {data.mcp_servers.map((item) => (
-
- ))}
-
-
-
-
{editVisible && (
= ({
-
{item.name}
+
+ {item.name}
+