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:
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;
|
||||
Reference in New Issue
Block a user