feat(knowledge): add overview page for knowledge base logs
- Implement new overview page to display file and dataset processing logs
This commit is contained in:
@@ -25,6 +25,7 @@ export const RunningStatusMap = {
|
|||||||
[RUNNING_STATUS_KEYS.DONE]: 'Success',
|
[RUNNING_STATUS_KEYS.DONE]: 'Success',
|
||||||
[RUNNING_STATUS_KEYS.FAIL]: 'Failed',
|
[RUNNING_STATUS_KEYS.FAIL]: 'Failed',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const MODEL_VARIABLE_TYPES = Object.freeze({
|
export const MODEL_VARIABLE_TYPES = Object.freeze({
|
||||||
Improvise: 'Improvise',
|
Improvise: 'Improvise',
|
||||||
Precise: 'Precise',
|
Precise: 'Precise',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState, useEffect, useCallback, useMemo } from 'react';
|
import { useState, useEffect, useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import knowledgeService from '@/services/knowledge_service';
|
import knowledgeService from '@/services/knowledge_service';
|
||||||
import type { IKnowledge, IKnowledgeGraph, IKnowledgeResult } from '@/interfaces/database/knowledge';
|
import type { IKnowledge, IKnowledgeGraph, IKnowledgeResult, IOverviewTital, IFileLogList } from '@/interfaces/database/knowledge';
|
||||||
import type { IFetchKnowledgeListRequestBody, IFetchKnowledgeListRequestParams } from '@/interfaces/request/knowledge';
|
import type { IFetchKnowledgeListRequestBody, IFetchKnowledgeListRequestParams } from '@/interfaces/request/knowledge';
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
|
|
||||||
@@ -477,3 +477,161 @@ export const useKnowledgeBatchOperations = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* useKnowledgeOverview
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
const LOGS_TABS = {
|
||||||
|
FILE_LOGS: 'fileLogs',
|
||||||
|
DATASET_LOGS: 'datasetLogs',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
type LogTabs = typeof LOGS_TABS[keyof typeof LOGS_TABS]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 知识库详情页 - 概览数据获取Hook
|
||||||
|
*/
|
||||||
|
export interface UseKnowledgeOverviewReturn {
|
||||||
|
overview: IOverviewTital | null;
|
||||||
|
fileLogs: IFileLogList | null;
|
||||||
|
datasetLogs: IFileLogList | null;
|
||||||
|
loading: boolean;
|
||||||
|
error: string | null;
|
||||||
|
currentPage: number;
|
||||||
|
pageSize: number;
|
||||||
|
activeTab: LogTabs;
|
||||||
|
keywords: string;
|
||||||
|
setCurrentPage: (page: number) => void;
|
||||||
|
setPageSize: (size: number) => void;
|
||||||
|
setActiveTab: (tab: LogTabs) => void;
|
||||||
|
setKeywords: (keywords: string) => void;
|
||||||
|
refresh: () => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useKnowledgeOverview = (kb_id: string): UseKnowledgeOverviewReturn => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [overview, setOverview] = useState<IOverviewTital | null>(null);
|
||||||
|
const [fileLogs, setFileLogs] = useState<IFileLogList | null>(null);
|
||||||
|
const [datasetLogs, setDatasetLogs] = useState<IFileLogList | null>(null);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
const [pageSize, setPageSize] = useState(20);
|
||||||
|
const [activeTab, setActiveTab] = useState<LogTabs>(LOGS_TABS.FILE_LOGS);
|
||||||
|
const [keywords, setKeywordsState] = useState('');
|
||||||
|
|
||||||
|
const fetchOverviewTital = useCallback(async () => {
|
||||||
|
if (!kb_id) return;
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
const response = await knowledgeService.getKnowledgeBasicInfo({ kb_id });
|
||||||
|
if (response.data.code === 0) {
|
||||||
|
setOverview(response.data.data);
|
||||||
|
} else {
|
||||||
|
throw new Error(response.data.message || t('knowledgeHooks.fetchOverviewFailed'));
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
const errorMessage = err.response?.data?.message || err.message || t('knowledgeHooks.fetchOverviewFailed');
|
||||||
|
setError(errorMessage);
|
||||||
|
console.error('Failed to fetch overview tital:', err);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}, [kb_id]);
|
||||||
|
|
||||||
|
const fetchPipelineLogs = useCallback(async () => {
|
||||||
|
if (!kb_id) return;
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
const response = await knowledgeService.getDataPipelineLogs({
|
||||||
|
kb_id,
|
||||||
|
page: currentPage,
|
||||||
|
page_size: pageSize,
|
||||||
|
keywords,
|
||||||
|
});
|
||||||
|
if (response.data.code === 0) {
|
||||||
|
setFileLogs(response.data.data as IFileLogList);
|
||||||
|
} else {
|
||||||
|
throw new Error(response.data.message);
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
const errorMessage = err.response?.data?.message || err.message;
|
||||||
|
setError(errorMessage);
|
||||||
|
console.error('Failed to fetch data pipeline logs:', err);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}, [kb_id, currentPage, pageSize, keywords]);
|
||||||
|
|
||||||
|
const fetchPipelineDatasetLogs = useCallback(async () => {
|
||||||
|
if (!kb_id) return;
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
const response = await knowledgeService.getPipelineDatasetLogs({
|
||||||
|
kb_id,
|
||||||
|
page: currentPage,
|
||||||
|
page_size: pageSize,
|
||||||
|
keywords,
|
||||||
|
});
|
||||||
|
if (response.data.code === 0) {
|
||||||
|
setDatasetLogs(response.data.data as IFileLogList);
|
||||||
|
} else {
|
||||||
|
throw new Error(response.data.message);
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
const errorMessage = err.response?.data?.message || err.message;
|
||||||
|
setError(errorMessage);
|
||||||
|
console.error('Failed to fetch pipeline dataset logs:', err);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}, [kb_id, currentPage, pageSize, keywords]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchOverviewTital();
|
||||||
|
}, [fetchOverviewTital]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeTab === LOGS_TABS.FILE_LOGS) {
|
||||||
|
fetchPipelineLogs();
|
||||||
|
} else {
|
||||||
|
fetchPipelineDatasetLogs();
|
||||||
|
}
|
||||||
|
}, [activeTab, fetchPipelineLogs, fetchPipelineDatasetLogs]);
|
||||||
|
|
||||||
|
// 设置关键词并重置到第一页
|
||||||
|
const setKeywords = useCallback((kw: string) => {
|
||||||
|
setKeywordsState(kw);
|
||||||
|
setCurrentPage(1);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const refresh = useCallback(async () => {
|
||||||
|
await Promise.all([
|
||||||
|
fetchOverviewTital(),
|
||||||
|
fetchPipelineLogs(),
|
||||||
|
fetchPipelineDatasetLogs(),
|
||||||
|
]);
|
||||||
|
}, [fetchOverviewTital, fetchPipelineLogs, fetchPipelineDatasetLogs]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
overview,
|
||||||
|
fileLogs,
|
||||||
|
datasetLogs,
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
|
currentPage,
|
||||||
|
pageSize,
|
||||||
|
activeTab,
|
||||||
|
keywords,
|
||||||
|
setCurrentPage,
|
||||||
|
setPageSize,
|
||||||
|
setActiveTab,
|
||||||
|
setKeywords,
|
||||||
|
refresh,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { RunningStatus } from '@/constants/knowledge';
|
import { RunningStatusMap, type RunningStatus } from '@/constants/knowledge';
|
||||||
import type { IDocumentInfo } from './document';
|
import type { IDocumentInfo } from './document';
|
||||||
|
|
||||||
|
|
||||||
@@ -491,3 +491,55 @@ export interface IKnowledgeGraph {
|
|||||||
/** 思维导图数据(已注释) */
|
/** 思维导图数据(已注释) */
|
||||||
// mind_map: TreeData;
|
// mind_map: TreeData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 文档日志项接口 */
|
||||||
|
export interface IDocumentLog {
|
||||||
|
fileName: string;
|
||||||
|
status: RunningStatus;
|
||||||
|
statusName: typeof RunningStatusMap[keyof typeof RunningStatusMap];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 日志统计项接口 */
|
||||||
|
export interface IOverviewTital {
|
||||||
|
cancelled: number;
|
||||||
|
failed: number;
|
||||||
|
finished: number;
|
||||||
|
processing: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 日志项接口 */
|
||||||
|
export interface IFileLogItem {
|
||||||
|
create_date: string;
|
||||||
|
create_time: number;
|
||||||
|
document_id: string;
|
||||||
|
document_name: string;
|
||||||
|
document_suffix: string;
|
||||||
|
document_type: string;
|
||||||
|
dsl: any;
|
||||||
|
path: string[];
|
||||||
|
task_id: string;
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
kb_id: string;
|
||||||
|
operation_status: string;
|
||||||
|
parser_id: string;
|
||||||
|
pipeline_id: string;
|
||||||
|
pipeline_title: string;
|
||||||
|
avatar: string;
|
||||||
|
process_begin_at: null | string;
|
||||||
|
process_duration: number;
|
||||||
|
progress: number;
|
||||||
|
progress_msg: string;
|
||||||
|
source_from: string;
|
||||||
|
status: string;
|
||||||
|
task_type: string;
|
||||||
|
tenant_id: string;
|
||||||
|
update_date: string;
|
||||||
|
update_time: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 日志列表接口 */
|
||||||
|
export interface IFileLogList {
|
||||||
|
logs: Array<IFileLogItem & IDocumentLog>;
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|||||||
@@ -427,6 +427,7 @@ export default {
|
|||||||
raptor: 'Raptor',
|
raptor: 'Raptor',
|
||||||
processingType: 'Processing Type',
|
processingType: 'Processing Type',
|
||||||
dataPipeline: 'Data Pipeline',
|
dataPipeline: 'Data Pipeline',
|
||||||
|
ingestionPipeline: 'Ingestion Pipeline',
|
||||||
operations: 'Operations',
|
operations: 'Operations',
|
||||||
taskId: 'Task ID',
|
taskId: 'Task ID',
|
||||||
duration: 'Duration',
|
duration: 'Duration',
|
||||||
@@ -453,6 +454,7 @@ export default {
|
|||||||
retrievalTestingDescription:
|
retrievalTestingDescription:
|
||||||
'Conduct a retrieval test to check if RAGFlow can recover the intended content for the LLM.',
|
'Conduct a retrieval test to check if RAGFlow can recover the intended content for the LLM.',
|
||||||
Parse: 'Parse',
|
Parse: 'Parse',
|
||||||
|
file: 'File',
|
||||||
dataset: 'Dataset',
|
dataset: 'Dataset',
|
||||||
testing: 'Retrieval testing',
|
testing: 'Retrieval testing',
|
||||||
files: 'files',
|
files: 'files',
|
||||||
|
|||||||
@@ -421,6 +421,7 @@ export default {
|
|||||||
raptor: 'Raptor',
|
raptor: 'Raptor',
|
||||||
processingType: '处理类型',
|
processingType: '处理类型',
|
||||||
dataPipeline: '数据管道',
|
dataPipeline: '数据管道',
|
||||||
|
ingestionPipeline: '摄取管道',
|
||||||
operations: '操作',
|
operations: '操作',
|
||||||
taskId: '任务ID',
|
taskId: '任务ID',
|
||||||
duration: '耗时',
|
duration: '耗时',
|
||||||
@@ -447,6 +448,7 @@ export default {
|
|||||||
retrievalTestingDescription:
|
retrievalTestingDescription:
|
||||||
'进行检索测试,检查 RAGFlow 是否能够为大语言模型(LLM)恢复预期的内容。',
|
'进行检索测试,检查 RAGFlow 是否能够为大语言模型(LLM)恢复预期的内容。',
|
||||||
Parse: '解析',
|
Parse: '解析',
|
||||||
|
file: '文件',
|
||||||
dataset: '知识库',
|
dataset: '知识库',
|
||||||
testing: '检索测试',
|
testing: '检索测试',
|
||||||
configuration: '配置',
|
configuration: '配置',
|
||||||
|
|||||||
@@ -4,18 +4,20 @@ import {
|
|||||||
Dashboard as DashboardIcon,
|
Dashboard as DashboardIcon,
|
||||||
Search as TestIcon,
|
Search as TestIcon,
|
||||||
Settings as ConfigIcon,
|
Settings as ConfigIcon,
|
||||||
|
ListAlt as OverviewIcon,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
interface FloatingActionButtonsProps {
|
interface FloatingActionButtonsProps {
|
||||||
onTestClick: () => void;
|
onTestClick: () => void;
|
||||||
onConfigClick: () => void;
|
onConfigClick: () => void;
|
||||||
|
onOverviewClick: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FloatingActionButtons: React.FC<FloatingActionButtonsProps> = ({
|
const FloatingActionButtons: React.FC<FloatingActionButtonsProps> = ({
|
||||||
onTestClick,
|
onTestClick,
|
||||||
onConfigClick,
|
onConfigClick,
|
||||||
|
onOverviewClick,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -30,6 +32,11 @@ const FloatingActionButtons: React.FC<FloatingActionButtonsProps> = ({
|
|||||||
name: t('knowledge.configSettings'),
|
name: t('knowledge.configSettings'),
|
||||||
onClick: onConfigClick,
|
onClick: onConfigClick,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: <OverviewIcon />,
|
||||||
|
name: t('knowledgeDetails.overview'),
|
||||||
|
onClick: onOverviewClick,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -405,6 +405,7 @@ function KnowledgeBaseDetail() {
|
|||||||
<FloatingActionButtons
|
<FloatingActionButtons
|
||||||
onTestClick={() => navigate(`/knowledge/${id}/testing`)}
|
onTestClick={() => navigate(`/knowledge/${id}/testing`)}
|
||||||
onConfigClick={() => navigate(`/knowledge/${id}/setting`)}
|
onConfigClick={() => navigate(`/knowledge/${id}/setting`)}
|
||||||
|
onOverviewClick={() => navigate(`/knowledge/${id}/overview`)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 上传文件对话框 */}
|
{/* 上传文件对话框 */}
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ export { default as KnowledgeBaseCreate } from './create';
|
|||||||
export { default as KnowledgeBaseDetail } from './detail'
|
export { default as KnowledgeBaseDetail } from './detail'
|
||||||
export { default as KnowledgeBaseSetting } from './setting';
|
export { default as KnowledgeBaseSetting } from './setting';
|
||||||
export { default as KnowledgeBaseTesting } from './testing';
|
export { default as KnowledgeBaseTesting } from './testing';
|
||||||
|
export { default as KnowledgeLogsPage } from './overview';
|
||||||
162
src/pages/knowledge/overview.tsx
Normal file
162
src/pages/knowledge/overview.tsx
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Box, Grid, Paper, Typography, IconButton, TextField, Tabs, Tab } from '@mui/material';
|
||||||
|
import { DataGrid, type GridColDef } from '@mui/x-data-grid';
|
||||||
|
import FilterListIcon from '@mui/icons-material/FilterList';
|
||||||
|
import SearchIcon from '@mui/icons-material/Search';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { useKnowledgeOverview } from '@/hooks/knowledge-hooks';
|
||||||
|
import type { IDocumentLog, IFileLogItem } from '@/interfaces/database/knowledge';
|
||||||
|
import logger from '@/utils/logger';
|
||||||
|
import i18n, { LanguageAbbreviation } from '@/locales';
|
||||||
|
import { enUS, zhCN } from '@mui/x-data-grid/locales';
|
||||||
|
|
||||||
|
|
||||||
|
const PROCESSING_TYPES = {
|
||||||
|
knowledgeGraph: 'GraphRAG',
|
||||||
|
raptor: 'RAPTOR',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
type ProcessingType = typeof PROCESSING_TYPES[keyof typeof PROCESSING_TYPES]
|
||||||
|
|
||||||
|
const ProcessingTypeMap = {
|
||||||
|
[PROCESSING_TYPES.knowledgeGraph]: 'Knowledge Graph',
|
||||||
|
[PROCESSING_TYPES.raptor]: 'RAPTOR',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
function KnowledgeLogsPage() {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [paginationModel, setPaginationModel] = React.useState({ page: 0, pageSize: 50 });
|
||||||
|
|
||||||
|
// 根据当前语言获取DataGrid的localeText
|
||||||
|
const getDataGridLocale = () => {
|
||||||
|
const currentLanguage = i18n.language;
|
||||||
|
return currentLanguage === LanguageAbbreviation.Zh ? zhCN : enUS;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 路由参数与数据Hook
|
||||||
|
const { id: kbId = '' } = useParams();
|
||||||
|
const {
|
||||||
|
overview,
|
||||||
|
fileLogs,
|
||||||
|
datasetLogs,
|
||||||
|
loading,
|
||||||
|
currentPage,
|
||||||
|
pageSize,
|
||||||
|
setCurrentPage,
|
||||||
|
setPageSize,
|
||||||
|
activeTab,
|
||||||
|
keywords,
|
||||||
|
setActiveTab,
|
||||||
|
setKeywords,
|
||||||
|
} = useKnowledgeOverview(kbId);
|
||||||
|
|
||||||
|
// 同步分页模型到Hook
|
||||||
|
React.useEffect(() => {
|
||||||
|
setPaginationModel({ page: Math.max(currentPage - 1, 0), pageSize });
|
||||||
|
}, [currentPage, pageSize]);
|
||||||
|
|
||||||
|
const columnsFile: GridColDef[] = [
|
||||||
|
{ field: 'id', headerName: 'ID', width: 100 },
|
||||||
|
{
|
||||||
|
field: 'document_name', headerName: t('knowledgeDetails.fileName'), flex: 1, minWidth: 160, valueGetter: (params) => {
|
||||||
|
logger.info('params', params)
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ field: 'source_from', headerName: t('knowledgeDetails.source'), flex: 1, minWidth: 140 },
|
||||||
|
{ field: 'pipeline_title', headerName: t('knowledgeDetails.ingestionPipeline'), flex: 1, minWidth: 180 },
|
||||||
|
{ field: 'create_date', headerName: t('knowledgeDetails.startDate') || 'Start Date', flex: 0.8, minWidth: 160, sortable: true },
|
||||||
|
{ field: 'task_type', headerName: t('knowledgeDetails.task') || 'Task', flex: 0.8, minWidth: 140 },
|
||||||
|
{ field: 'status', headerName: t('knowledgeDetails.status'), flex: 0.7, minWidth: 120 },
|
||||||
|
{ field: 'operations', headerName: t('knowledgeDetails.operations') || 'Operations', flex: 0.8, minWidth: 160, sortable: false, filterable: false, align: 'center', headerAlign: 'center' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const columnsDataset: GridColDef[] = [
|
||||||
|
{ field: 'id', headerName: 'ID', width: 100 },
|
||||||
|
{ field: 'create_date', headerName: t('knowledgeDetails.startDate') || 'Start Date', flex: 1, minWidth: 160, sortable: true },
|
||||||
|
{ field: 'task_type', headerName: 'Processing Type', flex: 1, minWidth: 180 },
|
||||||
|
{ field: 'status', headerName: t('knowledgeDetails.status'), flex: 0.8, minWidth: 120 },
|
||||||
|
{ field: 'operations', headerName: t('knowledgeDetails.operations') || 'Operations', flex: 0.8, minWidth: 160, sortable: false, filterable: false, align: 'center', headerAlign: 'center' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const columns = React.useMemo(() => (activeTab === 'fileLogs' ?
|
||||||
|
columnsFile :
|
||||||
|
columnsDataset),
|
||||||
|
[activeTab]);
|
||||||
|
const rows = React.useMemo(() => (activeTab === 'fileLogs' ?
|
||||||
|
(fileLogs?.logs || []) :
|
||||||
|
(datasetLogs?.logs || [])),
|
||||||
|
[activeTab, fileLogs, datasetLogs]);
|
||||||
|
const rowCount = React.useMemo(() => (activeTab === 'fileLogs' ?
|
||||||
|
(fileLogs?.total || 0) :
|
||||||
|
(datasetLogs?.total || 0)),
|
||||||
|
[activeTab, fileLogs, datasetLogs]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ p: 3 }}>
|
||||||
|
{/* 顶部统计卡片占位 */}
|
||||||
|
<Grid container spacing={2} sx={{ mb: 2 }}>
|
||||||
|
<Grid size={{ xs: 12, md: 4 }}>
|
||||||
|
<Paper sx={{ p: 2 }}>
|
||||||
|
<Typography variant="subtitle2">{t('datasetOverview.totalFiles')}</Typography>
|
||||||
|
<Typography variant="h4" sx={{ mt: 1 }}>{fileLogs?.total ?? 0}</Typography>
|
||||||
|
<Typography variant="caption" color="text.secondary">0% from last week</Typography>
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
<Grid size={{ xs: 12, md: 4 }}>
|
||||||
|
<Paper sx={{ p: 2 }}>
|
||||||
|
<Typography variant="subtitle2">{t('datasetOverview.downloading')}</Typography>
|
||||||
|
<Typography variant="h4" sx={{ mt: 1 }}>0</Typography>
|
||||||
|
<Typography variant="caption" color="text.secondary">{t('knowledgeDetails.success')} {overview?.finished ?? 0} · {t('knowledgeDetails.failed')} {overview?.failed ?? 0}</Typography>
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
<Grid size={{ xs: 12, md: 4 }}>
|
||||||
|
<Paper sx={{ p: 2 }}>
|
||||||
|
<Typography variant="subtitle2">{t('datasetOverview.processing')}</Typography>
|
||||||
|
<Typography variant="h4" sx={{ mt: 1 }}>{overview?.processing ?? 0}</Typography>
|
||||||
|
<Typography variant="caption" color="text.secondary">{t('knowledgeDetails.success')} {overview?.finished ?? 0} · {t('knowledgeDetails.failed')} {overview?.failed ?? 0}</Typography>
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* Tabs & Filter/Search */}
|
||||||
|
<Box display="flex" alignItems="center" gap={2} sx={{ mb: 2 }}>
|
||||||
|
<Tabs value={activeTab} onChange={(_, v) => setActiveTab(v)}>
|
||||||
|
<Tab value="file" label={t('knowledgeDetails.file')} />
|
||||||
|
<Tab value="dataset" label={t('knowledgeDetails.dataset')} />
|
||||||
|
</Tabs>
|
||||||
|
{/* <IconButton aria-label="filter"><FilterListIcon /></IconButton> */}
|
||||||
|
<Box display="flex" alignItems="center" gap={1} sx={{ ml: 'auto' }}>
|
||||||
|
<SearchIcon color="action" />
|
||||||
|
<TextField size="small" placeholder={t('common.search')} value={keywords} onChange={(e) => setKeywords(e.target.value)} />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* DataGrid 表格占位 */}
|
||||||
|
<Paper variant="outlined" sx={{ height: 420 }}>
|
||||||
|
<DataGrid
|
||||||
|
columns={columns}
|
||||||
|
rows={rows}
|
||||||
|
getRowId={(row) => row.id}
|
||||||
|
density="comfortable"
|
||||||
|
pageSizeOptions={[20, 50, 100]}
|
||||||
|
paginationMode="server"
|
||||||
|
rowCount={rowCount}
|
||||||
|
paginationModel={paginationModel}
|
||||||
|
onPaginationModelChange={(model) => {
|
||||||
|
setPaginationModel(model);
|
||||||
|
setCurrentPage(model.page + 1);
|
||||||
|
setPageSize(model.pageSize);
|
||||||
|
}}
|
||||||
|
loading={loading}
|
||||||
|
disableColumnMenu
|
||||||
|
localeText={getDataGridLocale().components.MuiDataGrid.defaultProps.localeText}
|
||||||
|
/>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default KnowledgeLogsPage;
|
||||||
@@ -10,7 +10,8 @@ import {
|
|||||||
KnowledgeBaseCreate,
|
KnowledgeBaseCreate,
|
||||||
KnowledgeBaseDetail,
|
KnowledgeBaseDetail,
|
||||||
KnowledgeBaseSetting,
|
KnowledgeBaseSetting,
|
||||||
KnowledgeBaseTesting
|
KnowledgeBaseTesting,
|
||||||
|
KnowledgeLogsPage
|
||||||
} from '../pages/knowledge';
|
} from '../pages/knowledge';
|
||||||
import {
|
import {
|
||||||
ModelsSetting,
|
ModelsSetting,
|
||||||
@@ -40,6 +41,7 @@ const AppRoutes = () => {
|
|||||||
<Route path="testing" element={<KnowledgeBaseTesting />} />
|
<Route path="testing" element={<KnowledgeBaseTesting />} />
|
||||||
<Route index element={<KnowledgeBaseDetail />} />
|
<Route index element={<KnowledgeBaseDetail />} />
|
||||||
<Route path="setting" element={<KnowledgeBaseSetting />} />
|
<Route path="setting" element={<KnowledgeBaseSetting />} />
|
||||||
|
<Route path="overview" element={<KnowledgeLogsPage />} />
|
||||||
</Route>
|
</Route>
|
||||||
</Route>
|
</Route>
|
||||||
<Route index element={<KnowledgeBaseList />} />
|
<Route index element={<KnowledgeBaseList />} />
|
||||||
|
|||||||
@@ -47,9 +47,10 @@ export default {
|
|||||||
getMeta: `${api_host}/kb/get_meta`,
|
getMeta: `${api_host}/kb/get_meta`,
|
||||||
getKnowledgeBasicInfo: `${api_host}/kb/basic_info`,
|
getKnowledgeBasicInfo: `${api_host}/kb/basic_info`,
|
||||||
// data pipeline log
|
// data pipeline log
|
||||||
fetchDataPipelineLog: `${api_host}/kb/list_pipeline_logs`,
|
fetchDataPipelineLogs: `${api_host}/kb/list_pipeline_logs`,
|
||||||
get_pipeline_detail: `${api_host}/kb/pipeline_log_detail`,
|
get_pipeline_detail: `${api_host}/kb/pipeline_log_detail`,
|
||||||
fetchPipelineDatasetLogs: `${api_host}/kb/list_pipeline_dataset_logs`,
|
fetchPipelineDatasetLogs: `${api_host}/kb/list_pipeline_dataset_logs`,
|
||||||
|
// run pipeline
|
||||||
runGraphRag: `${api_host}/kb/run_graphrag`,
|
runGraphRag: `${api_host}/kb/run_graphrag`,
|
||||||
traceGraphRag: `${api_host}/kb/trace_graphrag`,
|
traceGraphRag: `${api_host}/kb/trace_graphrag`,
|
||||||
runRaptor: `${api_host}/kb/run_raptor`,
|
runRaptor: `${api_host}/kb/run_raptor`,
|
||||||
|
|||||||
@@ -251,11 +251,11 @@ const knowledgeService = {
|
|||||||
// ===== 数据管道 =====
|
// ===== 数据管道 =====
|
||||||
|
|
||||||
// 获取数据管道日志
|
// 获取数据管道日志
|
||||||
getDataPipelineLog: (
|
getDataPipelineLogs: (
|
||||||
params?: IFetchKnowledgeListRequestParams,
|
params?: IFetchKnowledgeListRequestParams,
|
||||||
body?: IFetchDocumentListRequestBody
|
body?: IFetchDocumentListRequestBody
|
||||||
) => {
|
) => {
|
||||||
return request.post(api.fetchDataPipelineLog, body || {}, { params });
|
return request.post(api.fetchDataPipelineLogs, body || {}, { params });
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取管道详情
|
// 获取管道详情
|
||||||
|
|||||||
Reference in New Issue
Block a user