diff --git a/web/public/iconfont.js b/web/public/iconfont.js index d717db4d5..12cb9978c 100644 --- a/web/public/iconfont.js +++ b/web/public/iconfont.js @@ -1,5 +1,57 @@ (window._iconfont_svg_string_4909832 = - ''), + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + ''), ((h) => { var a = (l = (l = document.getElementsByTagName('script'))[ l.length - 1 diff --git a/web/src/assets/svg/data-flow/data-icon-bri.svg b/web/src/assets/svg/data-flow/data-icon-bri.svg new file mode 100644 index 000000000..355ea9090 --- /dev/null +++ b/web/src/assets/svg/data-flow/data-icon-bri.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/web/src/assets/svg/data-flow/data-icon.svg b/web/src/assets/svg/data-flow/data-icon.svg new file mode 100644 index 000000000..eddb6a3ba --- /dev/null +++ b/web/src/assets/svg/data-flow/data-icon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/web/src/assets/svg/data-flow/knowledgegraph.svg b/web/src/assets/svg/data-flow/knowledgegraph.svg deleted file mode 100644 index b0feec924..000000000 --- a/web/src/assets/svg/data-flow/knowledgegraph.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/data-flow/processing-icon-bri.svg b/web/src/assets/svg/data-flow/processing-icon-bri.svg new file mode 100644 index 000000000..96c8e7699 --- /dev/null +++ b/web/src/assets/svg/data-flow/processing-icon-bri.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/web/src/assets/svg/data-flow/processing-icon.svg b/web/src/assets/svg/data-flow/processing-icon.svg new file mode 100644 index 000000000..46acc8c1d --- /dev/null +++ b/web/src/assets/svg/data-flow/processing-icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/web/src/assets/svg/data-flow/raptor.svg b/web/src/assets/svg/data-flow/raptor.svg deleted file mode 100644 index 8f83bffc2..000000000 --- a/web/src/assets/svg/data-flow/raptor.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/data-flow/total-files-icon-bri.svg b/web/src/assets/svg/data-flow/total-files-icon-bri.svg new file mode 100644 index 000000000..795b5f540 --- /dev/null +++ b/web/src/assets/svg/data-flow/total-files-icon-bri.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/web/src/assets/svg/data-flow/total-files-icon.svg b/web/src/assets/svg/data-flow/total-files-icon.svg new file mode 100644 index 000000000..702e30909 --- /dev/null +++ b/web/src/assets/svg/data-flow/total-files-icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/web/src/components/file-status-badge.tsx b/web/src/components/file-status-badge.tsx index ad681eb34..1744fcd98 100644 --- a/web/src/components/file-status-badge.tsx +++ b/web/src/components/file-status-badge.tsx @@ -1,24 +1,28 @@ // src/pages/dataset/file-logs/file-status-badge.tsx import { FC } from 'react'; - +/** + * params: status: 0 not run yet 1 running, 2 cancel, 3 success, 4 fail + */ interface StatusBadgeProps { - status: 'Success' | 'Failed' | 'Running' | 'Pending'; + // status: 'Success' | 'Failed' | 'Running' | 'Pending'; + status: 0 | 1 | 2 | 3 | 4; + name?: string; } -const FileStatusBadge: FC = ({ status }) => { +const FileStatusBadge: FC = ({ status, name }) => { const getStatusColor = () => { // #3ba05c → rgb(59, 160, 92) // state-success // #d8494b → rgb(216, 73, 75) // state-error // #00beb4 → rgb(0, 190, 180) // accent-primary // #faad14 → rgb(250, 173, 20) // state-warning switch (status) { - case 'Success': + case 3: return `bg-[rgba(59,160,92,0.1)] text-state-success`; - case 'Failed': + case 4: return `bg-[rgba(216,73,75,0.1)] text-state-error`; - case 'Running': + case 1: return `bg-[rgba(0,190,180,0.1)] text-accent-primary`; - case 'Pending': + case 0: return `bg-[rgba(250,173,20,0.1)] text-state-warning`; default: return 'bg-gray-500/10 text-white'; @@ -31,13 +35,13 @@ const FileStatusBadge: FC = ({ status }) => { // #00beb4 → rgb(0, 190, 180) // accent-primary // #faad14 → rgb(250, 173, 20) // state-warning switch (status) { - case 'Success': + case 3: return `bg-[rgba(59,160,92,1)] text-state-success`; - case 'Failed': + case 4: return `bg-[rgba(216,73,75,1)] text-state-error`; - case 'Running': + case 1: return `bg-[rgba(0,190,180,1)] text-accent-primary`; - case 'Pending': + case 0: return `bg-[rgba(250,173,20,1)] text-state-warning`; default: return 'bg-gray-500/10 text-white'; @@ -46,10 +50,10 @@ const FileStatusBadge: FC = ({ status }) => { return (
- {status} + {name || ''}
); }; diff --git a/web/src/components/icon-font.tsx b/web/src/components/icon-font.tsx index a0b9a8e12..7c6436d90 100644 --- a/web/src/components/icon-font.tsx +++ b/web/src/components/icon-font.tsx @@ -4,6 +4,7 @@ import { getExtension } from '@/utils/document-util'; type IconFontType = { name: string; + className?: string; }; @@ -13,6 +14,23 @@ export const IconFont = ({ name, className }: IconFontType) => ( ); +export function IconFontFill({ + name, + className, + isFill = true, +}: IconFontType & { isFill?: boolean }) { + return ( + + + + + + ); +} + export function FileIcon({ name, className, diff --git a/web/src/components/ui/modal/modal.tsx b/web/src/components/ui/modal/modal.tsx index 9126f826a..de078c9df 100644 --- a/web/src/components/ui/modal/modal.tsx +++ b/web/src/components/ui/modal/modal.tsx @@ -187,7 +187,7 @@ const Modal: ModalType = ({ )} {/* content */} -
+
{destroyOnClose && !open ? null : children}
diff --git a/web/src/constants/knowledge.ts b/web/src/constants/knowledge.ts index 6839f383f..391016358 100644 --- a/web/src/constants/knowledge.ts +++ b/web/src/constants/knowledge.ts @@ -57,6 +57,7 @@ export enum LlmModelType { export enum KnowledgeSearchParams { DocumentId = 'doc_id', KnowledgeId = 'id', + Type = 'type', } export enum DocumentType { diff --git a/web/src/hooks/logic-hooks/navigate-hooks.ts b/web/src/hooks/logic-hooks/navigate-hooks.ts index b403b37ec..9aa0893f0 100644 --- a/web/src/hooks/logic-hooks/navigate-hooks.ts +++ b/web/src/hooks/logic-hooks/navigate-hooks.ts @@ -87,7 +87,7 @@ export const useNavigatePage = () => { (id: string, knowledgeId?: string) => () => { navigate( // `${Routes.ParsedResult}/${id}?${QueryStringMap.KnowledgeId}=${knowledgeId}`, - `${Routes.ParsedResult}/chunks?id=${knowledgeId}&doc_id=${id}`, + `${Routes.DataflowResult}?id=${knowledgeId}&doc_id=${id}&type=chunk`, ); }, [navigate], @@ -129,7 +129,7 @@ export const useNavigatePage = () => { (id: string, knowledgeId?: string) => () => { navigate( // `${Routes.ParsedResult}/${id}?${QueryStringMap.KnowledgeId}=${knowledgeId}`, - `${Routes.DataflowResult}/${id}`, + `${Routes.DataflowResult}?id=${knowledgeId}&doc_id=${id}&type=dataflow`, ); }, [navigate], diff --git a/web/src/hooks/route-hook.ts b/web/src/hooks/route-hook.ts index f015eaba3..baa5b23d9 100644 --- a/web/src/hooks/route-hook.ts +++ b/web/src/hooks/route-hook.ts @@ -29,6 +29,7 @@ export const useGetKnowledgeSearchParams = () => { const [currentQueryParameters] = useSearchParams(); return { + type: currentQueryParameters.get(KnowledgeSearchParams.Type) || '', documentId: currentQueryParameters.get(KnowledgeSearchParams.DocumentId) || '', knowledgeId: diff --git a/web/src/pages/dataflow-result/index.tsx b/web/src/pages/dataflow-result/index.tsx index f607f9266..96e7d549b 100644 --- a/web/src/pages/dataflow-result/index.tsx +++ b/web/src/pages/dataflow-result/index.tsx @@ -19,6 +19,7 @@ import { QueryStringMap, useNavigatePage, } from '@/hooks/logic-hooks/navigate-hooks'; +import { useGetKnowledgeSearchParams } from '@/hooks/route-hook'; import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request'; import { ChunkerContainer } from './chunker'; import { useGetDocumentUrl } from './components/document-preview/hooks'; @@ -60,6 +61,7 @@ const Chunk = () => { const handleStepChange = (id: number | string) => { setActiveStepId(id); }; + const { type } = useGetKnowledgeSearchParams(); return ( <> @@ -87,12 +89,14 @@ const Chunk = () => { -
- -
+ {type === 'dataflow' && ( +
+ +
+ )}
@@ -110,7 +114,8 @@ const Chunk = () => {
- {activeStepId === TimelineNodeObj.chunker.id && } + {(activeStepId === TimelineNodeObj.chunker.id || + type === 'chunk') && } {activeStepId === TimelineNodeObj.parser.id && }
diff --git a/web/src/pages/dataset/dataset-overview/dataset-common.ts b/web/src/pages/dataset/dataset-overview/dataset-common.ts index 9581ff6b6..3d3167a46 100644 --- a/web/src/pages/dataset/dataset-overview/dataset-common.ts +++ b/web/src/pages/dataset/dataset-overview/dataset-common.ts @@ -3,7 +3,7 @@ export enum LogTabs { DATASET_LOGS = 'datasetLogs', } -export enum processingType { +export enum ProcessingType { knowledgeGraph = 'knowledgeGraph', raptor = 'raptor', } diff --git a/web/src/pages/dataset/dataset-overview/index.tsx b/web/src/pages/dataset/dataset-overview/index.tsx index 19b74a12b..d67b60667 100644 --- a/web/src/pages/dataset/dataset-overview/index.tsx +++ b/web/src/pages/dataset/dataset-overview/index.tsx @@ -1,10 +1,8 @@ -import { - CircleQuestionMark, - Cpu, - FileChartLine, - HardDriveDownload, -} from 'lucide-react'; -import { FC, useState } from 'react'; +import SvgIcon from '@/components/svg-icon'; +import { useIsDarkTheme } from '@/components/theme-provider'; +import { toFixed } from '@/utils/common-util'; +import { CircleQuestionMark } from 'lucide-react'; +import { FC, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { LogTabs } from './dataset-common'; import { DatasetFilter } from './dataset-filter'; @@ -37,44 +35,43 @@ const StatCard: FC = ({ title, value, children, icon }) => { interface CardFooterProcessProps { total: number; - completed: number; success: number; failed: number; } const CardFooterProcess: FC = ({ total, - completed, - success, - failed, + success = 0, + failed = 0, }) => { const { t } = useTranslation(); - const successPrecentage = (success / total) * 100; - const failedPrecentage = (failed / total) * 100; + const successPrecentage = total ? (success / total) * 100 : 0; + const failedPrecentage = total ? (failed / total) * 100 : 0; + const completedPercentage = total ? ((success + failed) / total) * 100 : 0; return (
- {success} + {success || 0} {t('knowledgeDetails.success')}
- {failed} + {failed || 0} {t('knowledgeDetails.failed')}
- {completed} + {toFixed(completedPercentage) as string}% {t('knowledgeDetails.completed')}
-
+
@@ -86,24 +83,67 @@ const FileLogsPage: FC = () => { 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' : 'kiki’s demo', - startDate: '14/03/2025 14:53:39', - task: i === 0 ? 'chunck' : 'Parser', - status: - i === 0 - ? 'Success' - : i === 1 - ? 'Failed' - : i === 2 - ? 'Running' - : 'Pending', - })); + const topMockData = { + totalFiles: { + value: 2827, + precent: 12.5, + }, + downloads: { + value: 28, + success: 8, + failed: 2, + }, + processing: { + value: 156, + success: 8, + failed: 2, + }, + }; + const mockData = useMemo(() => { + if (active === LogTabs.FILE_LOGS) { + return 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' : 'kiki’s demo', + startDate: '14/03/2025 14:53:39', + task: i === 0 ? 'chunck' : 'Parser', + status: i === 0 ? 3 : i === 1 ? 4 : i === 2 ? 1 : 0, + statusName: + i === 0 + ? 'Success' + : i === 1 + ? 'Failed' + : i === 2 + ? 'Running' + : 'Pending', + })); + } + if (active === LogTabs.DATASET_LOGS) { + return Array(8) + .fill(0) + .map((_, i) => ({ + id: i === 0 ? '952734' : `14`, + fileName: 'PRD for DealBees 1.2 (1).txt', + source: 'GitHub', + startDate: '14/03/2025 14:53:39', + task: i === 0 ? 'chunck' : 'Parser', + pipeline: + i === 0 ? 'data demo for...' : i === 1 ? 'test' : 'kiki’s demo', + status: + i === 0 + ? 'Success' + : i === 1 + ? 'Failed' + : i === 2 + ? 'Running' + : 'Pending', + })); + } + }, [active]); const pagination = { current: 1, @@ -118,23 +158,63 @@ const FileLogsPage: FC = () => { console.log('Pagination changed:', { page, pageSize }); }; + const isDark = useIsDarkTheme(); return (
{/* Stats Cards */}
- }> -
+7% from last week
+ + ) : ( + + ) + } + > +
+ + {topMockData.totalFiles.precent > 0 ? '+' : ''} + {topMockData.totalFiles.precent}%{' '} + + from last week +
- }> + + ) : ( + + ) + } + > - }> - + + ) : ( + + ) + } + > +
diff --git a/web/src/pages/dataset/dataset-overview/overview-table.tsx b/web/src/pages/dataset/dataset-overview/overview-table.tsx index 0efd87cb8..6b9083c4c 100644 --- a/web/src/pages/dataset/dataset-overview/overview-table.tsx +++ b/web/src/pages/dataset/dataset-overview/overview-table.tsx @@ -14,10 +14,10 @@ import { } from '@/components/ui/table'; import { useTranslate } from '@/hooks/common-hooks'; import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; -import ProcessLogModal from '@/pages/datasets/process-log-modal'; import { ColumnDef, ColumnFiltersState, + Row, SortingState, flexRender, getCoreRowModel, @@ -29,7 +29,8 @@ import { import { TFunction } from 'i18next'; import { ClipboardList, Eye } from 'lucide-react'; import { Dispatch, FC, SetStateAction, useMemo, useState } from 'react'; -import { LogTabs, processingType } from './dataset-common'; +import ProcessLogModal from '../process-log-modal'; +import { LogTabs, ProcessingType } from './dataset-common'; interface DocumentLog { id: string; @@ -144,7 +145,12 @@ export const getFileLogsTableColumns = ( { accessorKey: 'status', header: t('status'), - cell: ({ row }) => , + cell: ({ row }) => ( + + ), }, { id: 'operations', @@ -179,7 +185,7 @@ export const getFileLogsTableColumns = ( export const getDatasetLogsTableColumns = ( t: TFunction<'translation', string>, - setIsModalVisible: Dispatch>, + showLog: (row: Row, active: LogTabs) => void, ) => { // const { t } = useTranslate('knowledgeDetails'); const columns: ColumnDef[] = [ @@ -221,10 +227,10 @@ export const getDatasetLogsTableColumns = ( header: t('processingType'), cell: ({ row }) => (
- {processingType.knowledgeGraph === row.original.processingType && ( + {ProcessingType.knowledgeGraph === row.original.processingType && ( )} - {processingType.raptor === row.original.processingType && ( + {ProcessingType.raptor === row.original.processingType && ( )} {row.original.processingType} @@ -234,7 +240,12 @@ export const getDatasetLogsTableColumns = ( { accessorKey: 'status', header: t('status'), - cell: ({ row }) => , + cell: ({ row }) => ( + + ), }, { id: 'operations', @@ -246,7 +257,7 @@ export const getDatasetLogsTableColumns = ( size="sm" className="p-1" onClick={() => { - setIsModalVisible(true); + showLog(row, LogTabs.DATASET_LOGS); }} > @@ -259,6 +270,18 @@ export const getDatasetLogsTableColumns = ( return columns; }; +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: + '\n17:43:21 Task has been received.\n17:43:25 Page(1~100000001): Start to parse.\n17:43:25 Page(1~100000001): Start to tag for every chunk ...\n17:43:45 Page(1~100000001): Tagging 2 chunks completed in 18.99s\n17:43:45 Page(1~100000001): Generate 2 chunks\n17:43:55 Page(1~100000001): Embedding chunks (10.60s)\n17:43:55 Page(1~100000001): Indexing done (0.07s). Task done (33.97s)\n17:43:58 created task raptor\n17:43:58 Task has been received.\n17:44:36 Cluster one layer: 2 -> 1\n17:44:36 Indexing done (0.05s). Task done (37.88s)\n17:44:40 created task graphrag\n17:44:41 Task has been received.\n17:50:57 Entities extraction of chunk 0 1/3 done, 25 nodes, 26 edges, 14893 tokens.\n17:56:01 [ERROR][Exception]: Operation timed out after 7200 seconds and 1 attempts.', +}; const FileLogsTable: FC = ({ data, pagination, @@ -272,11 +295,16 @@ const FileLogsTable: FC = ({ const { t } = useTranslate('knowledgeDetails'); const [isModalVisible, setIsModalVisible] = useState(false); const { navigateToDataflowResult } = useNavigatePage(); + const [logInfo, setLogInfo] = useState(taskInfo); + const showLog = (row: Row, active: LogTabs) => { + setLogInfo(row.original); + setIsModalVisible(true); + }; + const columns = useMemo(() => { - console.log('columns', active); return active === LogTabs.FILE_LOGS ? getFileLogsTableColumns(t, setIsModalVisible, navigateToDataflowResult) - : getDatasetLogsTableColumns(t, setIsModalVisible); + : getDatasetLogsTableColumns(t, showLog); }, [active, t]); const currentPagination = useMemo( @@ -308,18 +336,6 @@ const FileLogsTable: FC = ({ ? 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: - '\n17:43:21 Task has been received.\n17:43:25 Page(1~100000001): Start to parse.\n17:43:25 Page(1~100000001): Start to tag for every chunk ...\n17:43:45 Page(1~100000001): Tagging 2 chunks completed in 18.99s\n17:43:45 Page(1~100000001): Generate 2 chunks\n17:43:55 Page(1~100000001): Embedding chunks (10.60s)\n17:43:55 Page(1~100000001): Indexing done (0.07s). Task done (33.97s)\n17:43:58 created task raptor\n17:43:58 Task has been received.\n17:44:36 Cluster one layer: 2 -> 1\n17:44:36 Indexing done (0.05s). Task done (37.88s)\n17:44:40 created task graphrag\n17:44:41 Task has been received.\n17:50:57 Entities extraction of chunk 0 1/3 done, 25 nodes, 26 edges, 14893 tokens.\n17:56:01 [ERROR][Exception]: Operation timed out after 7200 seconds and 1 attempts.', - }; return (
@@ -364,7 +380,7 @@ const FileLogsTable: FC = ({ )}
-
+
= ({ setIsModalVisible(false)} - taskInfo={taskInfo} + logInfo={logInfo} />
); diff --git a/web/src/pages/dataset/dataset/dataset-table.tsx b/web/src/pages/dataset/dataset/dataset-table.tsx index 2182ec2d6..524a8ba14 100644 --- a/web/src/pages/dataset/dataset/dataset-table.tsx +++ b/web/src/pages/dataset/dataset/dataset-table.tsx @@ -29,6 +29,8 @@ import { useFetchDocumentList } from '@/hooks/use-document-request'; import { getExtension } from '@/utils/document-util'; import { pick } from 'lodash'; import { useMemo } from 'react'; +import ProcessLogModal from '../process-log-modal'; +import { useShowLog } from './hooks'; import { SetMetaDialog } from './set-meta-dialog'; import { useChangeDocumentParser } from './use-change-document-parser'; import { useDatasetTableColumns } from './use-dataset-table-columns'; @@ -81,11 +83,13 @@ export function DatasetTable({ onSetMetaModalOk, metaRecord, } = useSaveMeta(); + const { showLog, logInfo, logVisible, hideLog } = useShowLog(documents); const columns = useDatasetTableColumns({ showChangeParserModal, showRenameModal, showSetMetaModal, + showLog, }); const currentPagination = useMemo(() => { @@ -207,6 +211,13 @@ export function DatasetTable({ initialMetaData={metaRecord.meta_fields} > )} + {logVisible && ( + hideLog()} + logInfo={logInfo} + /> + )}
); } diff --git a/web/src/pages/dataset/dataset/generate-button/generate.tsx b/web/src/pages/dataset/dataset/generate-button/generate.tsx new file mode 100644 index 000000000..7b3fe75ae --- /dev/null +++ b/web/src/pages/dataset/dataset/generate-button/generate.tsx @@ -0,0 +1,113 @@ +import { IconFontFill } from '@/components/icon-font'; +import { Button } from '@/components/ui/button'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; +import { toFixed } from '@/utils/common-util'; +import { t } from 'i18next'; +import { lowerFirst } from 'lodash'; +import { CirclePause, WandSparkles } from 'lucide-react'; +import { useState } from 'react'; +import { generateStatus, useFetchGenerateData } from './hook'; + +const MenuItem: React.FC<{ name: 'KnowledgeGraph' | 'Raptor' }> = ({ + name, +}) => { + console.log(name, 'pppp'); + const iconKeyMap = { + KnowledgeGraph: 'knowledgegraph', + Raptor: 'dataflow-01', + }; + const { + data: { percent, type }, + pauseGenerate, + } = useFetchGenerateData(); + return ( +
+
+ + {t(`knowledgeDetails.${lowerFirst(name)}`)} +
+ {type === generateStatus.start && ( +
+ {t(`knowledgeDetails.generate${name}`)} +
+ )} + {type === generateStatus.running && ( +
+
+
+
+ {toFixed(percent) as string}% + { + pauseGenerate(); + }} + > + + +
+ )} +
+ ); +}; + +const Generate: React.FC = () => { + const [open, setOpen] = useState(false); + + const handleOpenChange = (isOpen: boolean) => { + setOpen(isOpen); + console.log('Dropdown is now', isOpen ? 'open' : 'closed'); + }; + + return ( +
+ + + + + + { + e.preventDefault(); + }} + onClick={(e) => { + e.stopPropagation(); + }} + > + + + { + e.preventDefault(); + }} + onClick={(e) => { + e.stopPropagation(); + }} + > + + + + +
+ ); +}; + +export default Generate; diff --git a/web/src/pages/dataset/dataset/generate-button/hook.ts b/web/src/pages/dataset/dataset/generate-button/hook.ts new file mode 100644 index 000000000..0be24a60d --- /dev/null +++ b/web/src/pages/dataset/dataset/generate-button/hook.ts @@ -0,0 +1,32 @@ +import { useQuery } from '@tanstack/react-query'; +import { useCallback } from 'react'; +export const generateStatus = { + running: 'running', + completed: 'completed', + start: 'start', +}; +const useFetchGenerateData = () => { + let number = 10; + // TODO: 获取数据 + const { data, isFetching: loading } = useQuery({ + queryKey: ['generateData', 'id'], + initialData: { id: 0, percent: 0, type: 'running' }, + gcTime: 0, + refetchInterval: 3000, + queryFn: async () => { + number += Math.random() * 10; + const data = { + id: Math.random(), + percent: number, + type: generateStatus.running, + }; + return data; + }, + }); + const pauseGenerate = useCallback(() => { + // TODO: pause generate + console.log('pause generate'); + }, []); + return { data, loading, pauseGenerate }; +}; +export { useFetchGenerateData }; diff --git a/web/src/pages/dataset/dataset/generate.tsx b/web/src/pages/dataset/dataset/generate.tsx deleted file mode 100644 index 6dad4d56f..000000000 --- a/web/src/pages/dataset/dataset/generate.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import SvgIcon from '@/components/svg-icon'; -import { Button } from '@/components/ui/button'; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu'; -import { t } from 'i18next'; -import { lowerFirst, toLower } from 'lodash'; -import { WandSparkles } from 'lucide-react'; - -const MenuItem: React.FC<{ name: 'KnowledgeGraph' | 'Raptor' }> = ({ - name, -}) => { - console.log(name, 'pppp'); - return ( -
-
- - {t(`knowledgeDetails.${lowerFirst(name)}`)} -
-
- {t(`knowledgeDetails.generate${name}`)} -
-
- ); -}; - -const Generate: React.FC = () => { - return ( -
- - - - - - - - - { - e.preventDefault(); - }} - onClick={(e) => { - e.stopPropagation(); - }} - > - - {/*
-
- - {t('knowledgeDetails.raptor')} -
-
{t('knowledgeDetails.generateRaptor')}
-
*/} -
-
-
-
- ); -}; - -export default Generate; diff --git a/web/src/pages/dataset/dataset/hooks.ts b/web/src/pages/dataset/dataset/hooks.ts index 1613f9cc9..5b44722cf 100644 --- a/web/src/pages/dataset/dataset/hooks.ts +++ b/web/src/pages/dataset/dataset/hooks.ts @@ -1,8 +1,10 @@ import { useSetModalState } from '@/hooks/common-hooks'; import { useNextWebCrawl } from '@/hooks/document-hooks'; import { useGetKnowledgeSearchParams } from '@/hooks/route-hook'; -import { useCallback, useState } from 'react'; +import { IDocumentInfo } from '@/interfaces/database/document'; +import { useCallback, useMemo, useState } from 'react'; import { useNavigate } from 'umi'; +import { ILogInfo } from '../process-log-modal'; export const useNavigateToOtherPage = () => { const navigate = useNavigate(); @@ -58,3 +60,41 @@ export const useHandleWebCrawl = () => { showWebCrawlUploadModal, }; }; + +export const useShowLog = (documents: IDocumentInfo[]) => { + const { showModal, hideModal, visible } = useSetModalState(); + const [record, setRecord] = useState(); + const logInfo = useMemo(() => { + const findRecord = documents.find( + (item: IDocumentInfo) => item.id === record?.id, + ); + let log: ILogInfo = { + taskId: record?.id, + fileName: record?.name || '-', + details: record?.progress_msg || '-', + }; + if (findRecord) { + log = { + taskId: findRecord.id, + fileName: findRecord.name, + fileSize: findRecord.size + '', + source: findRecord.source_type, + task: findRecord.status, + state: findRecord.run, + startTime: findRecord.process_begin_at, + endTime: findRecord.process_begin_at, + duration: findRecord.process_duration + 's', + details: findRecord.progress_msg, + }; + } + return log; + }, [record, documents]); + const showLog = useCallback( + (data: IDocumentInfo) => { + setRecord(data); + showModal(); + }, + [showModal], + ); + return { showLog, hideLog: hideModal, logVisible: visible, logInfo }; +}; diff --git a/web/src/pages/dataset/dataset/index.tsx b/web/src/pages/dataset/dataset/index.tsx index f7752c5c3..c3c63d6aa 100644 --- a/web/src/pages/dataset/dataset/index.tsx +++ b/web/src/pages/dataset/dataset/index.tsx @@ -15,7 +15,7 @@ import { useFetchDocumentList } from '@/hooks/use-document-request'; import { Upload } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { DatasetTable } from './dataset-table'; -import Generate from './generate'; +import Generate from './generate-button/generate'; import { useBulkOperateDataset } from './use-bulk-operate-dataset'; import { useCreateEmptyDocument } from './use-create-empty-document'; import { useSelectDatasetFilters } from './use-select-filters'; diff --git a/web/src/pages/dataset/dataset/parsing-card.tsx b/web/src/pages/dataset/dataset/parsing-card.tsx index d9cdefec3..17bc857f6 100644 --- a/web/src/pages/dataset/dataset/parsing-card.tsx +++ b/web/src/pages/dataset/dataset/parsing-card.tsx @@ -11,6 +11,7 @@ import { RunningStatus, RunningStatusMap } from './constant'; interface IProps { record: IDocumentInfo; + handleShowLog?: (record: IDocumentInfo) => void; } function Dot({ run }: { run: RunningStatus }) { @@ -85,11 +86,16 @@ export const PopoverContent = ({ record }: IProps) => { ); }; -export function ParsingCard({ record }: IProps) { +export function ParsingCard({ record, handleShowLog }: IProps) { return ( - diff --git a/web/src/pages/dataset/dataset/parsing-status-cell.tsx b/web/src/pages/dataset/dataset/parsing-status-cell.tsx index 8ada0b09d..8743e35b0 100644 --- a/web/src/pages/dataset/dataset/parsing-status-cell.tsx +++ b/web/src/pages/dataset/dataset/parsing-status-cell.tsx @@ -1,4 +1,5 @@ import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog'; +import { IconFontFill } from '@/components/icon-font'; import { Button } from '@/components/ui/button'; import { DropdownMenu, @@ -14,7 +15,7 @@ import { import { Progress } from '@/components/ui/progress'; import { Separator } from '@/components/ui/separator'; import { IDocumentInfo } from '@/interfaces/database/document'; -import { CircleX, RefreshCw } from 'lucide-react'; +import { CircleX } from 'lucide-react'; import { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { DocumentType, RunningStatus } from './constant'; @@ -28,16 +29,26 @@ const IconMap = {
), [RunningStatus.RUNNING]: , - [RunningStatus.CANCEL]: , - [RunningStatus.DONE]: , - [RunningStatus.FAIL]: , + [RunningStatus.CANCEL]: ( + + ), + [RunningStatus.DONE]: ( + + ), + [RunningStatus.FAIL]: ( + + ), }; export function ParsingStatusCell({ record, showChangeParserModal, showSetMetaModal, -}: { record: IDocumentInfo } & UseChangeDocumentParserShowType & + showLog, +}: { + record: IDocumentInfo; + showLog: (record: IDocumentInfo) => void; +} & UseChangeDocumentParserShowType & UseSaveMetaShowType) { const { t } = useTranslation(); const { run, parser_id, progress, chunk_num, id } = record; @@ -65,6 +76,9 @@ export function ParsingStatusCell({ return record.type !== DocumentType.Virtual; }, [record]); + const handleShowLog = (record: IDocumentInfo) => { + showLog(record); + }; return (
@@ -85,41 +99,64 @@ export function ParsingStatusCell({
{showParse && ( - <> -
); 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 fc492db13..762264b0c 100644 --- a/web/src/pages/dataset/dataset/use-dataset-table-columns.tsx +++ b/web/src/pages/dataset/dataset/use-dataset-table-columns.tsx @@ -23,12 +23,13 @@ import { UseSaveMetaShowType } from './use-save-meta'; type UseDatasetTableColumnsType = UseChangeDocumentParserShowType & UseRenameDocumentShowType & - UseSaveMetaShowType; + UseSaveMetaShowType & { showLog: (record: IDocumentInfo) => void }; export function useDatasetTableColumns({ showChangeParserModal, showRenameModal, showSetMetaModal, + showLog, }: UseDatasetTableColumnsType) { const { t } = useTranslation('translation', { keyPrefix: 'knowledgeDetails', @@ -151,6 +152,7 @@ export function useDatasetTableColumns({ record={row.original} showChangeParserModal={showChangeParserModal} showSetMetaModal={showSetMetaModal} + showLog={showLog} > ); }, diff --git a/web/src/pages/datasets/process-log-modal.tsx b/web/src/pages/dataset/process-log-modal.tsx similarity index 50% rename from web/src/pages/datasets/process-log-modal.tsx rename to web/src/pages/dataset/process-log-modal.tsx index 4d7315cd5..4a8f6ccd2 100644 --- a/web/src/pages/datasets/process-log-modal.tsx +++ b/web/src/pages/dataset/process-log-modal.tsx @@ -4,22 +4,23 @@ import { Modal } from '@/components/ui/modal/modal'; import { useTranslate } from '@/hooks/common-hooks'; import React from 'react'; import reactStringReplace from 'react-string-replace'; +export interface ILogInfo { + taskId?: string; + fileName: string; + fileSize?: string; + source?: string; + task?: string; + state?: 'Running' | 'Success' | 'Failed' | 'Pending'; + startTime?: string; + endTime?: string; + duration?: string; + details: string; +} interface ProcessLogModalProps { visible: boolean; onCancel: () => void; - taskInfo: { - taskId: string; - fileName: string; - fileSize: string; - source: string; - task: string; - state: 'Running' | 'Success' | 'Failed' | 'Pending'; - startTime: string; - endTime?: string; - duration?: string; - details: string; - }; + logInfo: ILogInfo; } const InfoItem: React.FC<{ @@ -38,9 +39,10 @@ const InfoItem: React.FC<{ const ProcessLogModal: React.FC = ({ visible, onCancel, - taskInfo, + logInfo, }) => { const { t } = useTranslate('knowledgeDetails'); + const blackKeyList = ['']; const replaceText = (text: string) => { // Remove duplicate \n const nextText = text.replace(/(\n)\1+/g, '$1'); @@ -71,47 +73,57 @@ const ProcessLogModal: React.FC = ({ } className="process-log-modal" > -
-
- {/* Left Column */} -
- - - - - -
- - {/* Right Column */} -
-
- Status -
- +
+
+ {Object.keys(logInfo).map((key) => { + if (blackKeyList.includes(key)) { + return null; + } + if (key === 'details') { + return ( +
+ + {replaceText(logInfo.details)} +
+ } + /> +
+ ); + } + if (key === 'Status') { + return ( +
+ Status +
+ +
+
+ ); + } + return ( +
+
-
- - - - - - -
+ ); + })}
- {/* */} -
+ {/* */} + {/*
Details
    - {replaceText(taskInfo.details)} + {replaceText(logInfo.details)}
-
+
*/}
); diff --git a/web/src/routes.ts b/web/src/routes.ts index c82f54c70..b09eceae9 100644 --- a/web/src/routes.ts +++ b/web/src/routes.ts @@ -287,7 +287,7 @@ const routes = [ ], }, { - path: `${Routes.DataflowResult}/:id`, + path: `${Routes.DataflowResult}`, layout: false, component: `@/pages${Routes.DataflowResult}`, },