Feat: Use data pipeline to visualize the parsing configuration of the knowledge base (#10423)

### What problem does this PR solve?

#9869

### Type of change

- [x] New Feature (non-breaking change which adds functionality)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: jinhai <haijin.chn@gmail.com>
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
Co-authored-by: chanx <1243304602@qq.com>
Co-authored-by: balibabu <cike8899@users.noreply.github.com>
Co-authored-by: Lynn <lynn_inf@hotmail.com>
Co-authored-by: 纷繁下的无奈 <zhileihuang@126.com>
Co-authored-by: huangzl <huangzl@shinemo.com>
Co-authored-by: writinwaters <93570324+writinwaters@users.noreply.github.com>
Co-authored-by: Wilmer <33392318@qq.com>
Co-authored-by: Adrian Weidig <adrianweidig@gmx.net>
Co-authored-by: Zhichang Yu <yuzhichang@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Yongteng Lei <yongtengrey@outlook.com>
Co-authored-by: Liu An <asiro@qq.com>
Co-authored-by: buua436 <66937541+buua436@users.noreply.github.com>
Co-authored-by: BadwomanCraZY <511528396@qq.com>
Co-authored-by: cucusenok <31804608+cucusenok@users.noreply.github.com>
Co-authored-by: Russell Valentine <russ@coldstonelabs.org>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Billy Bao <newyorkupperbay@gmail.com>
Co-authored-by: Zhedong Cen <cenzhedong2@126.com>
Co-authored-by: TensorNull <129579691+TensorNull@users.noreply.github.com>
Co-authored-by: TensorNull <tensor.null@gmail.com>
Co-authored-by: TeslaZY <TeslaZY@outlook.com>
Co-authored-by: Ajay <160579663+aybanda@users.noreply.github.com>
Co-authored-by: AB <aj@Ajays-MacBook-Air.local>
Co-authored-by: 天海蒼灆 <huangaoqin@tecpie.com>
Co-authored-by: He Wang <wanghechn@qq.com>
Co-authored-by: Atsushi Hatakeyama <atu729@icloud.com>
Co-authored-by: Jin Hai <haijin.chn@gmail.com>
Co-authored-by: Mohamed Mathari <155896313+melmathari@users.noreply.github.com>
Co-authored-by: Mohamed Mathari <nocodeventure@Mac-mini-van-Mohamed.fritz.box>
Co-authored-by: Stephen Hu <stephenhu@seismic.com>
Co-authored-by: Shaun Zhang <zhangwfjh@users.noreply.github.com>
Co-authored-by: zhimeng123 <60221886+zhimeng123@users.noreply.github.com>
Co-authored-by: mxc <mxc@example.com>
Co-authored-by: Dominik Novotný <50611433+SgtMarmite@users.noreply.github.com>
Co-authored-by: EVGENY M <168018528+rjohny55@users.noreply.github.com>
Co-authored-by: mcoder6425 <mcoder64@gmail.com>
Co-authored-by: lemsn <lemsn@msn.com>
Co-authored-by: lemsn <lemsn@126.com>
Co-authored-by: Adrian Gora <47756404+adagora@users.noreply.github.com>
Co-authored-by: Womsxd <45663319+Womsxd@users.noreply.github.com>
Co-authored-by: FatMii <39074672+FatMii@users.noreply.github.com>
This commit is contained in:
Kevin Hu
2025-10-09 12:36:19 +08:00
committed by GitHub
parent ef0aecea3b
commit cbf04ee470
490 changed files with 10630 additions and 30688 deletions

View File

@ -3,7 +3,12 @@ export enum LogTabs {
DATASET_LOGS = 'datasetLogs',
}
export enum processingType {
knowledgeGraph = 'knowledgeGraph',
raptor = 'raptor',
export enum ProcessingType {
knowledgeGraph = 'GraphRAG',
raptor = 'RAPTOR',
}
export const ProcessingTypeMap = {
[ProcessingType.knowledgeGraph]: 'Knowledge Graph',
[ProcessingType.raptor]: 'Raptor',
};

View File

@ -0,0 +1,96 @@
import { useHandleFilterSubmit } from '@/components/list-filter-bar/use-handle-filter-submit';
import {
useGetPaginationWithRouter,
useHandleSearchChange,
} from '@/hooks/logic-hooks';
import kbService, {
listDataPipelineLogDocument,
listPipelineDatasetLogs,
} from '@/services/knowledge-service';
import { useQuery } from '@tanstack/react-query';
import { useCallback, useState } from 'react';
import { useParams, useSearchParams } from 'umi';
import { LogTabs } from './dataset-common';
import { IFileLogList, IOverviewTital } from './interface';
const useFetchOverviewTital = () => {
const [searchParams] = useSearchParams();
const { id } = useParams();
const knowledgeBaseId = searchParams.get('id') || id;
const { data } = useQuery<IOverviewTital>({
queryKey: ['overviewTital'],
queryFn: async () => {
const { data: res = {} } = await kbService.getKnowledgeBasicInfo({
kb_id: knowledgeBaseId,
});
return res.data || [];
},
});
return { data };
};
const useFetchFileLogList = () => {
const [searchParams] = useSearchParams();
const { searchString, handleInputChange } = useHandleSearchChange();
const { pagination, setPagination } = useGetPaginationWithRouter();
const { filterValue, handleFilterSubmit } = useHandleFilterSubmit();
const { id } = useParams();
const [active, setActive] = useState<(typeof LogTabs)[keyof typeof LogTabs]>(
LogTabs.FILE_LOGS,
);
const knowledgeBaseId = searchParams.get('id') || id;
const fetchFunc =
active === LogTabs.DATASET_LOGS
? listPipelineDatasetLogs
: listDataPipelineLogDocument;
const { data } = useQuery<IFileLogList>({
queryKey: [
'fileLogList',
knowledgeBaseId,
pagination,
searchString,
active,
filterValue,
],
placeholderData: (previousData) => {
if (previousData === undefined) {
return { logs: [], total: 0 };
}
return previousData;
},
enabled: true,
queryFn: async () => {
const { data: res = {} } = await fetchFunc(
{
kb_id: knowledgeBaseId,
page: pagination.current,
page_size: pagination.pageSize,
keywords: searchString,
// order_by: '',
},
{ ...filterValue },
);
return res.data || [];
},
});
const onInputChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(
(e) => {
setPagination({ page: 1 });
handleInputChange(e);
},
[handleInputChange, setPagination],
);
return {
data,
searchString,
handleInputChange: onInputChange,
pagination: { ...pagination, total: data?.total },
setPagination,
active,
setActive,
filterValue,
handleFilterSubmit,
};
};
export { useFetchFileLogList, useFetchOverviewTital };

View File

@ -1,13 +1,16 @@
import {
CircleQuestionMark,
Cpu,
FileChartLine,
HardDriveDownload,
} from 'lucide-react';
import { FC, useState } from 'react';
import { FilterCollection } from '@/components/list-filter-bar/interface';
import SvgIcon from '@/components/svg-icon';
import { useIsDarkTheme } from '@/components/theme-provider';
import { AntToolTip } from '@/components/ui/tooltip';
import { useFetchDocumentList } from '@/hooks/use-document-request';
import { t } from 'i18next';
import { CircleQuestionMark } from 'lucide-react';
import { FC, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { RunningStatus, RunningStatusMap } from '../dataset/constant';
import { LogTabs } from './dataset-common';
import { DatasetFilter } from './dataset-filter';
import { useFetchFileLogList, useFetchOverviewTital } from './hook';
import FileLogsTable from './overview-table';
interface StatCardProps {
@ -15,15 +18,30 @@ interface StatCardProps {
value: number;
icon: JSX.Element;
children?: JSX.Element;
tooltip?: string;
}
interface CardFooterProcessProps {
success: number;
failed: number;
}
const StatCard: FC<StatCardProps> = ({ title, value, children, icon }) => {
const StatCard: FC<StatCardProps> = ({
title,
value,
children,
icon,
tooltip,
}) => {
return (
<div className="bg-bg-card p-4 rounded-lg border border-border flex flex-col gap-2">
<div className="flex items-center justify-between">
<h3 className="flex items-center gap-1 text-sm font-medium text-text-secondary">
{title}
<CircleQuestionMark size={12} />
{tooltip && (
<AntToolTip title={tooltip} trigger="hover">
<CircleQuestionMark size={12} />
</AntToolTip>
)}
</h3>
{icon}
</div>
@ -35,115 +53,228 @@ const StatCard: FC<StatCardProps> = ({ title, value, children, icon }) => {
);
};
interface CardFooterProcessProps {
total: number;
completed: number;
success: number;
failed: number;
}
const CardFooterProcess: FC<CardFooterProcessProps> = ({
total,
completed,
success,
failed,
success = 0,
failed = 0,
}) => {
const { t } = useTranslation();
const successPrecentage = (success / total) * 100;
const failedPrecentage = (failed / total) * 100;
return (
<div className="flex items-center flex-col gap-2">
<div className="flex justify-between w-full text-sm text-text-secondary">
<div className="flex items-center gap-2">
<div className="flex items-center gap-1">
{success}
<span>{t('knowledgeDetails.success')}</span>
<div className="w-full flex justify-between gap-4 rounded-lg text-sm font-bold text-text-primary">
<div className="flex items-center justify-between rounded-md w-1/2 p-2 bg-state-success-5">
<div className="flex items-center rounded-lg gap-1">
<div className="w-2 h-2 rounded-full bg-state-success "></div>
<div className="font-normal text-text-secondary text-xs">
{t('knowledgeDetails.success')}
</div>
</div>
<div className="flex items-center gap-1">
{failed}
<span>{t('knowledgeDetails.failed')}</span>
<div>{success || 0}</div>
</div>
<div className="flex items-center justify-between rounded-md w-1/2 bg-state-error-5 p-2">
<div className="flex items-center rounded-lg gap-1">
<div className="w-2 h-2 rounded-full bg-state-error"></div>
<div className="font-normal text-text-secondary text-xs">
{t('knowledgeDetails.failed')}
</div>
</div>
<div>{failed || 0}</div>
</div>
<div className="flex items-center gap-1">
{completed}
<span>{t('knowledgeDetails.completed')}</span>
</div>
</div>
<div className="w-full flex rounded-full h-3 bg-bg-card text-sm font-bold text-text-primary">
<div
className=" rounded-full h-3 bg-accent-primary"
style={{ width: successPrecentage + '%' }}
></div>
<div
className=" rounded-full h-3 bg-state-error"
style={{ width: failedPrecentage + '%' }}
></div>
</div>
</div>
);
};
const filters = [
{
field: 'operation_status',
label: t('knowledgeDetails.status'),
list: Object.values(RunningStatus).map((value) => {
// const value = key as RunningStatus;
console.log(value);
return {
id: value,
label: RunningStatusMap[value].label,
};
}),
},
{
field: 'types',
label: t('knowledgeDetails.task'),
list: [
{
id: 'Parse',
label: 'Parse',
},
{
id: 'Download',
label: 'Download',
},
],
},
];
const FileLogsPage: FC = () => {
const { t } = useTranslation();
const [active, setActive] = useState<(typeof LogTabs)[keyof typeof LogTabs]>(
LogTabs.FILE_LOGS,
);
const mockData = Array(30)
.fill(0)
.map((_, i) => ({
id: i === 0 ? '#952734' : `14`,
fileName: 'PRD for DealBees 1.2 (1).txt',
source: 'GitHub',
pipeline: i === 0 ? 'data demo for...' : i === 1 ? 'test' : 'kikis demo',
startDate: '14/03/2025 14:53:39',
task: i === 0 ? 'Parse' : 'Parser',
status:
i === 0
? 'Success'
: i === 1
? 'Failed'
: i === 2
? 'Running'
: 'Pending',
}));
const pagination = {
current: 1,
pageSize: 30,
total: 100,
};
const [topAllData, setTopAllData] = useState({
totalFiles: {
value: 0,
precent: 0,
},
downloads: {
value: 0,
success: 0,
failed: 0,
},
processing: {
value: 0,
success: 0,
failed: 0,
},
});
const { data: topData } = useFetchOverviewTital();
const {
pagination: { total: fileTotal },
} = useFetchDocumentList();
useEffect(() => {
setTopAllData((prev) => {
return {
...prev,
processing: {
value: topData?.processing || 0,
success: topData?.finished || 0,
failed: topData?.failed || 0,
},
};
});
}, [topData]);
useEffect(() => {
setTopAllData((prev) => {
return {
...prev,
totalFiles: {
value: fileTotal || 0,
precent: 0,
},
};
});
}, [fileTotal]);
const {
data: tableOriginData,
searchString,
handleInputChange,
pagination,
setPagination,
active,
filterValue,
handleFilterSubmit,
setActive,
} = useFetchFileLogList();
const tableList = useMemo(() => {
console.log('tableList', tableOriginData);
if (tableOriginData && tableOriginData.logs?.length) {
return tableOriginData.logs.map((item) => {
return {
...item,
fileName: item.document_name,
statusName: item.operation_status,
};
});
}
}, [tableOriginData]);
const changeActiveLogs = (active: (typeof LogTabs)[keyof typeof LogTabs]) => {
setActive(active);
};
const handlePaginationChange = (page: number, pageSize: number) => {
console.log('Pagination changed:', { page, pageSize });
setPagination({
...pagination,
page,
pageSize: pageSize,
});
};
const isDark = useIsDarkTheme();
return (
<div className="p-5 min-w-[880px] border-border border rounded-lg mr-5">
{/* Stats Cards */}
<div className="grid grid-cols-3 md:grid-cols-3 gap-4 mb-6">
<StatCard title="Total Files" value={2827} icon={<FileChartLine />}>
<div>+7% from last week</div>
<StatCard
title={t('datasetOverview.totalFiles')}
value={topAllData.totalFiles.value}
icon={
isDark ? (
<SvgIcon name="data-flow/total-files-icon" width={40} />
) : (
<SvgIcon name="data-flow/total-files-icon-bri" width={40} />
)
}
>
<div>
<span className="text-accent-primary">
{topAllData.totalFiles.precent > 0 ? '+' : ''}
{topAllData.totalFiles.precent}%{' '}
</span>
<span className="font-normal text-text-secondary text-xs">
from last week
</span>
</div>
</StatCard>
<StatCard title="Downloading" value={28} icon={<HardDriveDownload />}>
<StatCard
title={t('datasetOverview.downloading')}
value={topAllData.downloads.value}
icon={
isDark ? (
<SvgIcon name="data-flow/data-icon" width={40} />
) : (
<SvgIcon name="data-flow/data-icon-bri" width={40} />
)
}
tooltip={t('datasetOverview.downloadTip')}
>
<CardFooterProcess
total={100}
success={8}
failed={2}
completed={15}
success={topAllData.downloads.success}
failed={topAllData.downloads.failed}
/>
</StatCard>
<StatCard title="Processing" value={156} icon={<Cpu />}>
<CardFooterProcess total={20} success={8} failed={2} completed={15} />
<StatCard
title={t('datasetOverview.processing')}
value={topAllData.processing.value}
icon={
isDark ? (
<SvgIcon name="data-flow/processing-icon" width={40} />
) : (
<SvgIcon name="data-flow/processing-icon-bri" width={40} />
)
}
tooltip={t('datasetOverview.processingTip')}
>
<CardFooterProcess
success={topAllData.processing.success}
failed={topAllData.processing.failed}
/>
</StatCard>
</div>
{/* Tabs & Search */}
<DatasetFilter active={active} setActive={changeActiveLogs} />
<DatasetFilter
filters={filters as FilterCollection[]}
value={filterValue}
active={active}
setActive={changeActiveLogs}
searchString={searchString}
onSearchChange={handleInputChange}
onChange={handleFilterSubmit}
/>
{/* Table */}
<FileLogsTable
data={mockData}
data={tableList}
pagination={pagination}
setPagination={handlePaginationChange}
pageCount={10}

View File

@ -0,0 +1,62 @@
import { RunningStatus, RunningStatusMap } from '../dataset/constant';
import { LogTabs } from './dataset-common';
export interface DocumentLog {
fileName: string;
status: RunningStatus;
statusName: typeof RunningStatusMap;
}
export interface FileLogsTableProps {
data: Array<IFileLogItem & DocumentLog>;
pageCount: number;
pagination: {
current: number;
pageSize: number;
total: number;
};
setPagination: (pagination: { page: number; pageSize: number }) => void;
loading?: boolean;
active: (typeof LogTabs)[keyof typeof LogTabs];
}
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: IFileLogItem[];
total: number;
}

View File

@ -1,7 +1,6 @@
import FileStatusBadge from '@/components/file-status-badge';
import { FileIcon } from '@/components/icon-font';
import { FileIcon, IconFontFill } from '@/components/icon-font';
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
import SvgIcon from '@/components/svg-icon';
import { Button } from '@/components/ui/button';
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
import {
@ -12,12 +11,16 @@ import {
TableHeader,
TableRow,
} from '@/components/ui/table';
import { RunningStatusMap } from '@/constants/knowledge';
import { useTranslate } from '@/hooks/common-hooks';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import ProcessLogModal from '@/pages/datasets/process-log-modal';
import { PipelineResultSearchParams } from '@/pages/dataflow-result/constant';
import { NavigateToDataflowResultProps } from '@/pages/dataflow-result/interface';
import { formatDate, formatSecondsToHumanReadable } from '@/utils/date';
import {
ColumnDef,
ColumnFiltersState,
Row,
SortingState,
flexRender,
getCoreRowModel,
@ -27,62 +30,43 @@ import {
useReactTable,
} from '@tanstack/react-table';
import { TFunction } from 'i18next';
import { ClipboardList, Eye } from 'lucide-react';
import { Dispatch, FC, SetStateAction, useMemo, useState } from 'react';
import { LogTabs, processingType } from './dataset-common';
interface DocumentLog {
id: string;
fileName: string;
source: string;
pipeline: string;
startDate: string;
task: string;
status: 'Success' | 'Failed' | 'Running' | 'Pending';
}
interface FileLogsTableProps {
data: DocumentLog[];
pageCount: number;
pagination: {
current: number;
pageSize: number;
total: number;
};
setPagination: (pagination: { page: number; pageSize: number }) => void;
loading?: boolean;
active: (typeof LogTabs)[keyof typeof LogTabs];
}
import { ArrowUpDown, ClipboardList, Eye } from 'lucide-react';
import { FC, useMemo, useState } from 'react';
import { useParams } from 'umi';
import { RunningStatus } from '../dataset/constant';
import ProcessLogModal from '../process-log-modal';
import { LogTabs, ProcessingType, ProcessingTypeMap } from './dataset-common';
import { DocumentLog, FileLogsTableProps, IFileLogItem } from './interface';
export const getFileLogsTableColumns = (
t: TFunction<'translation', string>,
setIsModalVisible: Dispatch<SetStateAction<boolean>>,
showLog: (row: Row<IFileLogItem & DocumentLog>, active: LogTabs) => void,
kowledgeId: string,
navigateToDataflowResult: (
id: string,
knowledgeId?: string | undefined,
props: NavigateToDataflowResultProps,
) => () => void,
) => {
// const { t } = useTranslate('knowledgeDetails');
const columns: ColumnDef<DocumentLog>[] = [
{
id: 'select',
header: ({ table }) => (
<input
type="checkbox"
checked={table.getIsAllRowsSelected()}
onChange={table.getToggleAllRowsSelectedHandler()}
className="rounded bg-gray-900 text-blue-500 focus:ring-blue-500"
/>
),
cell: ({ row }) => (
<input
type="checkbox"
checked={row.getIsSelected()}
onChange={row.getToggleSelectedHandler()}
className="rounded border-gray-600 bg-gray-900 text-blue-500 focus:ring-blue-500"
/>
),
},
const columns: ColumnDef<IFileLogItem & DocumentLog>[] = [
// {
// id: 'select',
// header: ({ table }) => (
// <input
// type="checkbox"
// checked={table.getIsAllRowsSelected()}
// onChange={table.getToggleAllRowsSelectedHandler()}
// className="rounded bg-gray-900 text-blue-500 focus:ring-blue-500"
// />
// ),
// cell: ({ row }) => (
// <input
// type="checkbox"
// checked={row.getIsSelected()}
// onChange={row.getToggleSelectedHandler()}
// className="rounded border-gray-600 bg-gray-900 text-blue-500 focus:ring-blue-500"
// />
// ),
// },
{
accessorKey: 'id',
header: 'ID',
@ -96,10 +80,10 @@ export const getFileLogsTableColumns = (
cell: ({ row }) => (
<div
className="flex items-center gap-2 text-text-primary"
onClick={navigateToDataflowResult(
row.original.id,
row.original.kb_id,
)}
// onClick={navigateToDataflowResult(
// row.original.id,
// row.original.kb_id,
// )}
>
<FileIcon name={row.original.fileName}></FileIcon>
{row.original.fileName}
@ -107,68 +91,97 @@ export const getFileLogsTableColumns = (
),
},
{
accessorKey: 'source',
accessorKey: 'source_from',
header: t('source'),
cell: ({ row }) => (
<div className="text-text-primary">{row.original.source}</div>
<div className="text-text-primary">{row.original.source_from}</div>
),
},
{
accessorKey: 'pipeline',
accessorKey: 'pipeline_title',
header: t('dataPipeline'),
cell: ({ row }) => (
<div className="flex items-center gap-2 text-text-primary">
<RAGFlowAvatar
avatar={null}
name={row.original.pipeline}
avatar={row.original.avatar}
name={row.original.pipeline_title}
className="size-4"
/>
{row.original.pipeline}
{row.original.pipeline_title}
</div>
),
},
{
accessorKey: 'startDate',
header: t('startDate'),
accessorKey: 'process_begin_at',
header: ({ column }) => {
return (
<Button
variant="transparent"
className="border-none"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
{t('startDate')}
<ArrowUpDown />
</Button>
);
},
cell: ({ row }) => (
<div className="text-text-primary">{row.original.startDate}</div>
<div className="text-text-primary">
{formatDate(row.original.process_begin_at)}
</div>
),
},
{
accessorKey: 'task',
accessorKey: 'task_type',
header: t('task'),
cell: ({ row }) => (
<div className="text-text-primary">{row.original.task}</div>
<div className="text-text-primary">{row.original.task_type}</div>
),
},
{
accessorKey: 'status',
accessorKey: 'operation_status',
header: t('status'),
cell: ({ row }) => <FileStatusBadge status={row.original.status} />,
cell: ({ row }) => (
<FileStatusBadge
status={row.original.operation_status as RunningStatus}
name={
RunningStatusMap[row.original.operation_status as RunningStatus]
}
/>
),
},
{
id: 'operations',
header: t('operations'),
cell: ({ row }) => (
<div className="flex justify-start space-x-2">
<div className="flex justify-start space-x-2 opacity-0 group-hover:opacity-100 transition-opacity">
<Button
variant="ghost"
size="sm"
className="p-1"
onClick={() => {
setIsModalVisible(true);
showLog(row, LogTabs.FILE_LOGS);
}}
>
<Eye />
</Button>
<Button
variant="ghost"
size="sm"
className="p-1"
onClick={navigateToDataflowResult(row.original.id)}
>
<ClipboardList />
</Button>
{row.original.pipeline_id && (
<Button
variant="ghost"
size="sm"
className="p-1"
onClick={navigateToDataflowResult({
id: row.original.id,
[PipelineResultSearchParams.KnowledgeId]: kowledgeId,
[PipelineResultSearchParams.DocumentId]:
row.original.document_id,
[PipelineResultSearchParams.IsReadOnly]: 'false',
[PipelineResultSearchParams.Type]: 'dataflow',
})}
>
<ClipboardList />
</Button>
)}
</div>
),
},
@ -179,29 +192,29 @@ export const getFileLogsTableColumns = (
export const getDatasetLogsTableColumns = (
t: TFunction<'translation', string>,
setIsModalVisible: Dispatch<SetStateAction<boolean>>,
showLog: (row: Row<IFileLogItem & DocumentLog>, active: LogTabs) => void,
) => {
// const { t } = useTranslate('knowledgeDetails');
const columns: ColumnDef<DocumentLog>[] = [
{
id: 'select',
header: ({ table }) => (
<input
type="checkbox"
checked={table.getIsAllRowsSelected()}
onChange={table.getToggleAllRowsSelectedHandler()}
className="rounded bg-gray-900 text-blue-500 focus:ring-blue-500"
/>
),
cell: ({ row }) => (
<input
type="checkbox"
checked={row.getIsSelected()}
onChange={row.getToggleSelectedHandler()}
className="rounded border-gray-600 bg-gray-900 text-blue-500 focus:ring-blue-500"
/>
),
},
const columns: ColumnDef<IFileLogItem & DocumentLog>[] = [
// {
// id: 'select',
// header: ({ table }) => (
// <input
// type="checkbox"
// checked={table.getIsAllRowsSelected()}
// onChange={table.getToggleAllRowsSelectedHandler()}
// className="rounded bg-gray-900 text-blue-500 focus:ring-blue-500"
// />
// ),
// cell: ({ row }) => (
// <input
// type="checkbox"
// checked={row.getIsSelected()}
// onChange={row.getToggleSelectedHandler()}
// className="rounded border-gray-600 bg-gray-900 text-blue-500 focus:ring-blue-500"
// />
// ),
// },
{
accessorKey: 'id',
header: 'ID',
@ -210,43 +223,74 @@ export const getDatasetLogsTableColumns = (
),
},
{
accessorKey: 'startDate',
header: t('startDate'),
accessorKey: 'process_begin_at',
header: ({ column }) => {
return (
<Button
variant="transparent"
className="border-none"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
{t('startDate')}
<ArrowUpDown />
</Button>
);
},
cell: ({ row }) => (
<div className="text-text-primary">{row.original.startDate}</div>
),
},
{
accessorKey: 'processingType',
header: t('processingType'),
cell: ({ row }) => (
<div className="flex items-center gap-2 text-text-primary">
{processingType.knowledgeGraph === row.original.processingType && (
<SvgIcon name={`data-flow/knowledgegraph`} width={24}></SvgIcon>
)}
{processingType.raptor === row.original.processingType && (
<SvgIcon name={`data-flow/raptor`} width={24}></SvgIcon>
)}
{row.original.processingType}
<div className="text-text-primary">
{formatDate(row.original.process_begin_at)}
</div>
),
},
{
accessorKey: 'status',
accessorKey: 'task_type',
header: t('processingType'),
cell: ({ row }) => (
<div className="flex items-center gap-2 text-text-primary">
{ProcessingType.knowledgeGraph === row.original.task_type && (
<IconFontFill
name={`knowledgegraph`}
className="text-text-secondary"
></IconFontFill>
)}
{ProcessingType.raptor === row.original.task_type && (
<IconFontFill
name={`dataflow-01`}
className="text-text-secondary"
></IconFontFill>
)}
{ProcessingTypeMap[row.original.task_type as ProcessingType] ||
row.original.task_type}
</div>
),
},
{
accessorKey: 'operation_status',
header: t('status'),
cell: ({ row }) => <FileStatusBadge status={row.original.status} />,
cell: ({ row }) => (
// <FileStatusBadge
// status={row.original.status}
// name={row.original.statusName}
// />
<FileStatusBadge
status={row.original.operation_status as RunningStatus}
name={
RunningStatusMap[row.original.operation_status as RunningStatus]
}
/>
),
},
{
id: 'operations',
header: t('operations'),
cell: ({ row }) => (
<div className="flex justify-start space-x-2">
<div className="flex justify-start space-x-2 opacity-0 group-hover:opacity-100 transition-opacity">
<Button
variant="ghost"
size="sm"
className="p-1"
onClick={() => {
setIsModalVisible(true);
showLog(row, LogTabs.DATASET_LOGS);
}}
>
<Eye />
@ -272,11 +316,35 @@ const FileLogsTable: FC<FileLogsTableProps> = ({
const { t } = useTranslate('knowledgeDetails');
const [isModalVisible, setIsModalVisible] = useState(false);
const { navigateToDataflowResult } = useNavigatePage();
const [logInfo, setLogInfo] = useState<IFileLogItem>();
const kowledgeId = useParams().id;
const showLog = (row: Row<IFileLogItem & DocumentLog>) => {
const logDetail = {
taskId: row.original?.dsl?.task_id,
fileName: row.original.document_name,
source: row.original.source_from,
task: row.original?.task_type,
status: row.original.statusName,
startDate: formatDate(row.original.process_begin_at),
duration: formatSecondsToHumanReadable(
row.original.process_duration || 0,
),
details: row.original.progress_msg,
};
console.log('logDetail', logDetail);
setLogInfo(logDetail);
setIsModalVisible(true);
};
const columns = useMemo(() => {
console.log('columns', active);
return active === LogTabs.FILE_LOGS
? getFileLogsTableColumns(t, setIsModalVisible, navigateToDataflowResult)
: getDatasetLogsTableColumns(t, setIsModalVisible);
? getFileLogsTableColumns(
t,
showLog,
kowledgeId || '',
navigateToDataflowResult,
)
: getDatasetLogsTableColumns(t, showLog);
}, [active, t]);
const currentPagination = useMemo(
@ -287,8 +355,8 @@ const FileLogsTable: FC<FileLogsTableProps> = ({
[pagination],
);
const table = useReactTable({
data,
const table = useReactTable<IFileLogItem & DocumentLog>({
data: data || [],
columns,
manualPagination: true,
getCoreRowModel: getCoreRowModel(),
@ -308,19 +376,9 @@ const FileLogsTable: FC<FileLogsTableProps> = ({
? Math.ceil(pagination.total / pagination.pageSize)
: 0,
});
const taskInfo = {
taskId: '#9527',
fileName: 'PRD for DealBees 1.2 (1).text',
fileSize: '2.4G',
source: 'Github',
task: 'Parse',
state: 'Running',
startTime: '14/03/2025 14:53:39',
duration: '800',
details: 'PRD for DealBees 1.2 (1).text',
};
return (
<div className="w-full h-[calc(100vh-350px)]">
<div className="w-full h-[calc(100vh-360px)]">
<Table rootClassName="max-h-[calc(100vh-380px)]">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
@ -337,7 +395,7 @@ const FileLogsTable: FC<FileLogsTableProps> = ({
))}
</TableHeader>
<TableBody className="relative">
{table.getRowModel().rows.length ? (
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
@ -363,7 +421,7 @@ const FileLogsTable: FC<FileLogsTableProps> = ({
)}
</TableBody>
</Table>
<div className="flex items-center justify-end py-4 absolute bottom-3 right-12">
<div className="flex items-center justify-end absolute bottom-3 right-12">
<div className="space-x-2">
<RAGFlowPagination
{...{ current: pagination.current, pageSize: pagination.pageSize }}
@ -372,11 +430,14 @@ const FileLogsTable: FC<FileLogsTableProps> = ({
/>
</div>
</div>
<ProcessLogModal
visible={isModalVisible}
onCancel={() => setIsModalVisible(false)}
taskInfo={taskInfo}
/>
{isModalVisible && (
<ProcessLogModal
title={active === LogTabs.FILE_LOGS ? t('fileLogs') : t('datasetLog')}
visible={isModalVisible}
onCancel={() => setIsModalVisible(false)}
logInfo={logInfo}
/>
)}
</div>
);
};