From 32dfee803a8f69b6bfa8f39ede9e725272754195 Mon Sep 17 00:00:00 2001 From: zhaoying Date: Fri, 24 Apr 2026 18:05:01 +0800 Subject: [PATCH 1/2] feat(web): workflow app logs --- web/src/views/ApplicationConfig/Logs.tsx | 18 +++++++- .../components/LogDetailModal.tsx | 38 ++++++++++++++-- .../views/Workflow/components/Chat/Chat.tsx | 6 +-- .../Workflow/components/Chat/Runtime.tsx | 45 ++++++++++--------- .../views/Workflow/hooks/useWorkflowGraph.ts | 4 +- 5 files changed, 80 insertions(+), 31 deletions(-) diff --git a/web/src/views/ApplicationConfig/Logs.tsx b/web/src/views/ApplicationConfig/Logs.tsx index cf56059c..75a5bdec 100644 --- a/web/src/views/ApplicationConfig/Logs.tsx +++ b/web/src/views/ApplicationConfig/Logs.tsx @@ -7,7 +7,7 @@ import { type FC, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router-dom'; -import { Flex, Button } from 'antd'; +import { Flex, Button, Form } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import { getAppLogsUrl } from '@/api/application'; @@ -15,11 +15,14 @@ import Table from '@/components/Table' import { formatDateTime } from '@/utils/format'; import type { LogItem, LogDetailModalRef } from './types' import LogDetailModal from './components/LogDetailModal' +import SearchInput from '@/components/SearchInput' const Statistics: FC = () => { const { t } = useTranslation(); const { id } = useParams(); const logDetailRef = useRef(null); + const [form] = Form.useForm(); + const values = Form.useWatch([], form); const handleViewDetail = (item: LogItem) => { logDetailRef.current?.handleOpen(item); @@ -62,15 +65,26 @@ const Statistics: FC = () => { ]; return (
+ +
+ + + +
+
apiUrl={getAppLogsUrl(id || '')} apiParams={{ is_draft: false, + ...(values ?? {}) }} columns={columns} rowKey="id" isScroll={true} - scrollY="calc(100vh - 214px)" + scrollY="calc(100vh - 242px)" />
diff --git a/web/src/views/ApplicationConfig/components/LogDetailModal.tsx b/web/src/views/ApplicationConfig/components/LogDetailModal.tsx index 26d8741b..b37c3ae2 100644 --- a/web/src/views/ApplicationConfig/components/LogDetailModal.tsx +++ b/web/src/views/ApplicationConfig/components/LogDetailModal.tsx @@ -1,8 +1,8 @@ /* * @Author: ZhaoYing * @Date: 2026-03-24 16:31:24 - * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-24 16:31:24 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-04-24 17:49:58 */ import { forwardRef, useImperativeHandle, useState, useEffect } from 'react'; import { Flex, Button, Empty, Skeleton } from 'antd'; @@ -14,6 +14,12 @@ import { getAppLogDetail } from '@/api/application' import ChatContent from '@/components/Chat/ChatContent' import { formatDateTime } from '@/utils/format' import type { ChatItem } from '@/components/Chat/types' +import Runtime from '@/views/Workflow/components/Chat/Runtime' +import { nodeLibrary } from '@/views/Workflow/constant' + +const nodeIconMap = Object.fromEntries( + nodeLibrary.flatMap(c => c.nodes.map(n => [n.type, n.icon])) +) /** Log detail data with conversation messages */ type Data = LogItem & { @@ -54,7 +60,30 @@ const LogDetailModal = forwardRef((_props, ref) => { if (!vo) return setLoading(true) getAppLogDetail(vo.app_id, vo.id).then(res => { - setData(res as Data) + const { node_executions_map, messages, ...rest } = res as Data; + let hasSubContentMessages = messages + if (messages && messages.length > 0 && node_executions_map && Object.keys(node_executions_map).length > 0) { + hasSubContentMessages = messages.map(item => { + if (item.id && node_executions_map[item.id]) { + item.subContent = node_executions_map[item.id]?.map(({ input, output, cycle_items = [], error, process, ...node }: any) => { + const converted: any = { ...node, icon: nodeIconMap[node.node_type], content: { input, output, process, error } } + if (node.node_type === 'loop' && Array.isArray(cycle_items) && cycle_items.length > 0) { + converted.subContent = cycle_items.map(({ input: cInput, output: cOutput, error: cError, process: cProcess, ...cNode }: any) => ({ + ...cNode, + icon: nodeIconMap[cNode.node_type], + content: { input: cInput, output: cOutput, process: cProcess, error: cError } + })) + } + return converted + }) + } + return { ...item } + }) + } + setData({ + ...rest, + messages: hasSubContentMessages + }) }) .finally(() => { setLoading(false) @@ -66,6 +95,8 @@ const LogDetailModal = forwardRef((_props, ref) => { handleClose })); + console.log('data', data) + return ( @@ -92,6 +123,7 @@ const LogDetailModal = forwardRef((_props, ref) => { data={data.messages || []} streamLoading={false} labelFormat={(item) => formatDateTime(item.created_at)} + renderRuntime={(item, index) => } /> ) } diff --git a/web/src/views/Workflow/components/Chat/Chat.tsx b/web/src/views/Workflow/components/Chat/Chat.tsx index a6b4a2a8..820fe8c7 100644 --- a/web/src/views/Workflow/components/Chat/Chat.tsx +++ b/web/src/views/Workflow/components/Chat/Chat.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-06 21:10:56 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-04-21 14:59:13 + * @Last Modified time: 2026-04-24 17:34:51 */ /** * Workflow Chat Component @@ -66,7 +66,7 @@ const Chat = forwardRef([]) const [message, setMessage] = useState(undefined) - console.log('abortRef', abortRef) + console.log('abortRef', abortRef, chatList) /** * Opens the chat drawer and loads workflow variables from the start node @@ -305,7 +305,7 @@ const Chat = forwardRef = ({ )} {/* Display input and output data as JSON code blocks */} - {['input', 'output'].map(key => ( -
-
- {isLoop ? t(`workflow.runtime.${key}_cycle_vars`) : t(`workflow.${key}_result`)} - + {['input', 'process', 'output'].map(key => { + if (vo.node_type !== 'http-request' && key === 'process') return null + return ( +
+
+ {isLoop ? t(`workflow.runtime.${key}_cycle_vars`) : t(`workflow.${key}_result`)} + +
+
+ +
-
- -
-
- ))} + ) + })} ) }]} diff --git a/web/src/views/Workflow/hooks/useWorkflowGraph.ts b/web/src/views/Workflow/hooks/useWorkflowGraph.ts index f30db10f..a22ee6c0 100644 --- a/web/src/views/Workflow/hooks/useWorkflowGraph.ts +++ b/web/src/views/Workflow/hooks/useWorkflowGraph.ts @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 15:17:48 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-04-20 16:00:26 + * @Last Modified time: 2026-04-24 17:21:09 */ import { Clipboard, Graph, Keyboard, MiniMap, Node, Snapline, History, type Edge } from '@antv/x6'; import type { HistoryCommand as Command } from '@antv/x6/lib/plugin/history/type'; @@ -1492,7 +1492,7 @@ export const useWorkflowGraph = ({ // Reset all node execution status first nodes.forEach(node => { const data = node.getData(); - if (typeof data.status === 'string') { + if (typeof data.executionStatus === 'string') { node.setData({ ...data, executionStatus: undefined }); } }); From 2c864f63375fac9a4a7d9dfa5d74d695ac368970 Mon Sep 17 00:00:00 2001 From: zhaoying Date: Fri, 24 Apr 2026 18:15:01 +0800 Subject: [PATCH 2/2] feat(web): http request add process --- web/src/views/ApplicationConfig/TestChat/index.tsx | 9 ++++++--- web/src/views/Workflow/components/Chat/Chat.tsx | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/web/src/views/ApplicationConfig/TestChat/index.tsx b/web/src/views/ApplicationConfig/TestChat/index.tsx index b62efc6b..2fc66aa6 100644 --- a/web/src/views/ApplicationConfig/TestChat/index.tsx +++ b/web/src/views/ApplicationConfig/TestChat/index.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-03-13 17:27:52 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-04-07 21:48:30 + * @Last Modified time: 2026-04-24 18:14:25 */ import { type FC, useState, useRef, useEffect } from 'react' import { useTranslation } from 'react-i18next' @@ -59,6 +59,7 @@ interface NodeData { node_type?: string; input?: any; output?: any; + process?: any; elapsed_time?: string; error?: any; state: Record; @@ -485,7 +486,7 @@ const TestChat: FC = ({ } const updateWorkflowNodeEndMessage = (data: NodeData) => { - const { node_id, input, output, error, elapsed_time, status } = data; + const { node_id, input, output, process, error, elapsed_time, status } = data; setChatList(prev => { const newList = [...prev] const lastIndex = newList.length - 1 @@ -498,6 +499,7 @@ const TestChat: FC = ({ content: { input, output, + process, error, }, status: status || 'completed', @@ -514,7 +516,7 @@ const TestChat: FC = ({ } const updateWorkflowCycleMessage = (data: NodeData) => { - const { node_id, cycle_id, cycle_idx, input, output, error, elapsed_time, status } = data; + const { node_id, cycle_id, cycle_idx, input, output, process, error, elapsed_time, status } = data; const { nodes } = config as WorkflowConfig const node = nodes.find(n => n.id === node_id); const { name, type } = node || {} @@ -538,6 +540,7 @@ const TestChat: FC = ({ cycle_idx, input, output, + process, error, }, status: status || 'completed', diff --git a/web/src/views/Workflow/components/Chat/Chat.tsx b/web/src/views/Workflow/components/Chat/Chat.tsx index 820fe8c7..863825ba 100644 --- a/web/src/views/Workflow/components/Chat/Chat.tsx +++ b/web/src/views/Workflow/components/Chat/Chat.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-06 21:10:56 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-04-24 17:34:51 + * @Last Modified time: 2026-04-24 18:13:22 */ /** * Workflow Chat Component @@ -185,7 +185,7 @@ const Chat = forwardRef { data.forEach(item => { - const { content, conversation_id, node_id, cycle_id, cycle_idx, input, output, error, elapsed_time, status, citations } = item.data as { + const { content, conversation_id, node_id, cycle_id, cycle_idx, input, output, process, error, elapsed_time, status, citations } = item.data as { content: string; conversation_id: string | null; cycle_id: string; @@ -193,6 +193,7 @@ const Chat = forwardRef