Feat: Display the data flow log on the far right. #9869 (#10214)

### What problem does this PR solve?

Feat: Display the data flow log on the far right. #9869
### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-09-22 19:13:18 +08:00
committed by GitHub
parent 28afc7e67d
commit d0bfe8b10c
8 changed files with 43 additions and 10 deletions

View File

@ -1599,6 +1599,9 @@ This delimiter is used to split the input text into several text pieces echo of
serverType: 'Server Type', serverType: 'Server Type',
addMCP: 'Add MCP', addMCP: 'Add MCP',
editMCP: 'Edit MCP', editMCP: 'Edit MCP',
toolsAvailable: 'tools available',
mcpServers: 'MCP Servers',
customizeTheListOfMcpServers: 'Customize the list of MCP servers',
}, },
search: { search: {
searchApps: 'Search Apps', searchApps: 'Search Apps',
@ -1695,6 +1698,7 @@ This delimiter is used to split the input text into several text pieces echo of
filenameEmbdWeight: 'Filename embd weight', filenameEmbdWeight: 'Filename embd weight',
begin: 'File', begin: 'File',
parserMethod: 'Parser method', parserMethod: 'Parser method',
exportJson: 'Export JSON',
}, },
}, },
}; };

View File

@ -1510,6 +1510,17 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
okText: '确认', okText: '确认',
cancelText: '取消', cancelText: '取消',
}, },
mcp: {
export: '导出',
import: '导入',
url: 'URL',
serverType: '服务器类型',
addMCP: '添加 MCP',
editMCP: '编辑 MCP',
toolsAvailable: '可用的工具',
mcpServers: 'MCP 服务器',
customizeTheListOfMcpServers: '自定义 MCP 服务器列表',
},
search: { search: {
searchApps: '搜索', searchApps: '搜索',
createSearch: '创建查询', createSearch: '创建查询',
@ -1605,6 +1616,7 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
filenameEmbdWeight: '文件名嵌入权重', filenameEmbdWeight: '文件名嵌入权重',
begin: '文件', begin: '文件',
parserMethod: '解析方法', parserMethod: '解析方法',
exportJson: '导出 JSON',
}, },
}, },
}; };

View File

@ -153,7 +153,11 @@ function DataFlowCanvas({ drawerVisible, hideDrawer }: IProps) {
hideModal: hideLogSheet, hideModal: hideLogSheet,
} = useSetModalState(); } = useSetModalState();
const { run, loading: running, messageId } = useRunDataflow(showLogSheet!); const {
run,
loading: running,
messageId,
} = useRunDataflow(showLogSheet!, hideRunOrChatDrawer);
const onConnect = (connection: Connection) => { const onConnect = (connection: Connection) => {
originalOnConnect(connection); originalOnConnect(connection);

View File

@ -1,3 +1,4 @@
import { useFetchAgent } from '@/hooks/use-agent-request';
import { ITraceData } from '@/interfaces/database/agent'; import { ITraceData } from '@/interfaces/database/agent';
import { downloadJsonFile } from '@/utils/file-util'; import { downloadJsonFile } from '@/utils/file-util';
import { get, isEmpty } from 'lodash'; import { get, isEmpty } from 'lodash';
@ -22,12 +23,14 @@ export function isEndOutputEmpty(list?: ITraceData[]) {
return isEmpty(findEndOutput(list)); return isEmpty(findEndOutput(list));
} }
export function useDownloadOutput(data?: ITraceData[]) { export function useDownloadOutput(data?: ITraceData[]) {
const { data: agent } = useFetchAgent();
const handleDownloadJson = useCallback(() => { const handleDownloadJson = useCallback(() => {
const output = findEndOutput(data); const output = findEndOutput(data);
if (!isEndOutputEmpty(data)) { if (!isEndOutputEmpty(data)) {
downloadJsonFile(output, `output.json`); downloadJsonFile(output, `${agent.title}.json`);
} }
}, [data]); }, [agent.title, data]);
return { return {
handleDownloadJson, handleDownloadJson,

View File

@ -5,7 +5,10 @@ import { useCallback, useState } from 'react';
import { useParams } from 'umi'; import { useParams } from 'umi';
import { useSaveGraphBeforeOpeningDebugDrawer } from './use-save-graph'; import { useSaveGraphBeforeOpeningDebugDrawer } from './use-save-graph';
export function useRunDataflow(showLogSheet: () => void) { export function useRunDataflow(
showLogSheet: () => void,
hideRunOrChatDrawer: () => void,
) {
const { send } = useSendMessageBySSE(api.runCanvas); const { send } = useSendMessageBySSE(api.runCanvas);
const { id } = useParams(); const { id } = useParams();
const [messageId, setMessageId] = useState(); const [messageId, setMessageId] = useState();
@ -26,6 +29,7 @@ export function useRunDataflow(showLogSheet: () => void) {
if (res && res?.response.status === 200 && get(res, 'data.code') === 0) { if (res && res?.response.status === 200 && get(res, 'data.code') === 0) {
// fetch canvas // fetch canvas
hideRunOrChatDrawer();
const msgId = get(res, 'data.data.message_id'); const msgId = get(res, 'data.data.message_id');
if (msgId) { if (msgId) {
@ -35,7 +39,7 @@ export function useRunDataflow(showLogSheet: () => void) {
return msgId; return msgId;
} }
}, },
[id, saveGraph, send], [hideRunOrChatDrawer, id, saveGraph, send],
); );
return { run, loading: loading, messageId }; return { run, loading: loading, messageId };

View File

@ -10,6 +10,7 @@ import { IModalProps } from '@/interfaces/common';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { NotebookText, SquareArrowOutUpRight } from 'lucide-react'; import { NotebookText, SquareArrowOutUpRight } from 'lucide-react';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import 'react18-json-view/src/style.css'; import 'react18-json-view/src/style.css';
import { import {
isEndOutputEmpty, isEndOutputEmpty,
@ -20,6 +21,7 @@ import { DataflowTimeline } from './dataflow-timeline';
type LogSheetProps = IModalProps<any> & { messageId?: string }; type LogSheetProps = IModalProps<any> & { messageId?: string };
export function LogSheet({ hideModal, messageId }: LogSheetProps) { export function LogSheet({ hideModal, messageId }: LogSheetProps) {
const { t } = useTranslation();
const { setMessageId, data } = useFetchMessageTrace(false); const { setMessageId, data } = useFetchMessageTrace(false);
const { handleDownloadJson } = useDownloadOutput(data); const { handleDownloadJson } = useDownloadOutput(data);
@ -32,7 +34,7 @@ export function LogSheet({ hideModal, messageId }: LogSheetProps) {
return ( return (
<Sheet open onOpenChange={hideModal} modal={false}> <Sheet open onOpenChange={hideModal} modal={false}>
<SheetContent className={cn('top-20 right-[620px]')}> <SheetContent className={cn('top-20')}>
<SheetHeader> <SheetHeader>
<SheetTitle className="flex items-center gap-1"> <SheetTitle className="flex items-center gap-1">
<NotebookText className="size-4" /> <NotebookText className="size-4" />
@ -46,7 +48,7 @@ export function LogSheet({ hideModal, messageId }: LogSheetProps) {
className="w-full mt-8" className="w-full mt-8"
> >
<SquareArrowOutUpRight /> <SquareArrowOutUpRight />
Export JSON {t('dataflow.exportJson')}
</Button> </Button>
</section> </section>
</SheetContent> </SheetContent>

View File

@ -122,7 +122,11 @@ export function EditMcpDialog({
setFieldChanged={setFieldChanged} setFieldChanged={setFieldChanged}
></EditMcpForm> ></EditMcpForm>
<Collapse <Collapse
title={<div>{nextTools?.length || 0} tools available</div>} title={
<div>
{nextTools?.length || 0} {t('mcp.toolsAvailable')}
</div>
}
open={collapseOpen} open={collapseOpen}
onOpenChange={setCollapseOpen} onOpenChange={setCollapseOpen}
rightContent={ rightContent={

View File

@ -33,10 +33,10 @@ export default function McpServer() {
return ( return (
<section className="p-4 w-full"> <section className="p-4 w-full">
<div className="text-text-primary text-2xl">MCP Servers</div> <div className="text-text-primary text-2xl">{t('mcp.mcpServers')}</div>
<section className="flex items-center justify-between pb-5"> <section className="flex items-center justify-between pb-5">
<div className="text-text-secondary"> <div className="text-text-secondary">
Customize the list of MCP servers {t('mcp.customizeTheListOfMcpServers')}
</div> </div>
<div className="flex gap-5"> <div className="flex gap-5">
<SearchInput <SearchInput