diff --git a/web/app/components/workflow/hooks/use-workflow-run.ts b/web/app/components/workflow/hooks/use-workflow-run.ts
index 0462ef3e7d..76a9a43421 100644
--- a/web/app/components/workflow/hooks/use-workflow-run.ts
+++ b/web/app/components/workflow/hooks/use-workflow-run.ts
@@ -271,8 +271,14 @@ export const useWorkflowRun = () => {
setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
const currentIndex = draft.tracing!.findIndex(trace => trace.node_id === data.node_id)
- if (currentIndex > -1 && draft.tracing)
- draft.tracing[currentIndex] = data as any
+ if (currentIndex > -1 && draft.tracing) {
+ draft.tracing[currentIndex] = {
+ ...(draft.tracing[currentIndex].extras
+ ? { extras: draft.tracing[currentIndex].extras }
+ : {}),
+ ...data,
+ } as any
+ }
}))
const newNodes = produce(nodes, (draft) => {
diff --git a/web/app/components/workflow/panel/workflow-preview.tsx b/web/app/components/workflow/panel/workflow-preview.tsx
index c9a9bdd13b..661b106704 100644
--- a/web/app/components/workflow/panel/workflow-preview.tsx
+++ b/web/app/components/workflow/panel/workflow-preview.tsx
@@ -4,6 +4,7 @@ import {
} from 'react'
import cn from 'classnames'
import { useTranslation } from 'react-i18next'
+import OutputPanel from '../run/output-panel'
import ResultPanel from '../run/result-panel'
import TracingPanel from '../run/tracing-panel'
import { useStore } from '../store'
@@ -34,6 +35,13 @@ const WorkflowPreview = () => {
)}
onClick={() => switchTab('RESULT')}
>{t('runLog.result')}
+
switchTab('DETAIL')}
+ >{t('runLog.detail')}
{
onClick={() => switchTab('TRACING')}
>{t('runLog.tracing')}
-
+
{currentTab === 'RESULT' && (
+
+ )}
+ {currentTab === 'RESULT' && !workflowRunningData?.result && (
+
+
+
+ )}
+ {currentTab === 'DETAIL' && (
{
steps={workflowRunningData?.result?.total_steps}
/>
)}
- {currentTab === 'RESULT' && !workflowRunningData?.result && (
+ {currentTab === 'DETAIL' && !workflowRunningData?.result && (
diff --git a/web/app/components/workflow/run/index.tsx b/web/app/components/workflow/run/index.tsx
index 5f76cdd94b..82a59d8d82 100644
--- a/web/app/components/workflow/run/index.tsx
+++ b/web/app/components/workflow/run/index.tsx
@@ -4,6 +4,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { useContext } from 'use-context-selector'
import { useTranslation } from 'react-i18next'
import cn from 'classnames'
+import OutputPanel from './output-panel'
import ResultPanel from './result-panel'
import TracingPanel from './tracing-panel'
import { ToastContext } from '@/app/components/base/toast'
@@ -14,7 +15,7 @@ import type { WorkflowRunDetailResponse } from '@/models/log'
import { useStore as useAppStore } from '@/app/components/app/store'
export type RunProps = {
- activeTab?: 'RESULT' | 'TRACING'
+ activeTab?: 'RESULT' | 'DETAIL' | 'TRACING'
runID: string
getResultCallback?: (result: WorkflowRunDetailResponse) => void
}
@@ -100,6 +101,13 @@ const RunPanel: FC = ({ activeTab = 'RESULT', runID, getResultCallback
)}
onClick={() => switchTab('RESULT')}
>{t('runLog.result')}
+
switchTab('DETAIL')}
+ >{t('runLog.detail')}
= ({ activeTab = 'RESULT', runID, getResultCallback
>{t('runLog.tracing')}
{/* panel detal */}
-
+
{loading && (
)}
{!loading && currentTab === 'RESULT' && runDetail && (
+
+ )}
+ {!loading && currentTab === 'DETAIL' && runDetail && (
= ({ nodeInfo, className, hideInfo = false }) => {
!collapseState && 'rotate-90',
)}
/>
-
+
{nodeInfo.title}
{nodeInfo.status !== 'running' && !hideInfo && (
{`${getTime(nodeInfo.elapsed_time || 0)} · ${getTokenCount(nodeInfo.execution_metadata?.total_tokens || 0)} tokens`}
diff --git a/web/app/components/workflow/run/output-panel.tsx b/web/app/components/workflow/run/output-panel.tsx
new file mode 100644
index 0000000000..59fa7062e8
--- /dev/null
+++ b/web/app/components/workflow/run/output-panel.tsx
@@ -0,0 +1,48 @@
+'use client'
+import type { FC } from 'react'
+import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
+import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
+import { Markdown } from '@/app/components/base/markdown'
+
+type OutputPanelProps = {
+ outputs?: any
+ error?: string
+}
+
+const OutputPanel: FC = ({
+ outputs,
+ error,
+}) => {
+ return (
+
+ {error && (
+
+ )}
+ {!outputs && (
+
+
+
+ )}
+ {outputs && Object.keys(outputs).length === 1 && (
+
+
+
+ )}
+ {outputs && Object.keys(outputs).length > 1 && (
+
+
}
+ language={CodeLanguage.json}
+ value={outputs}
+ isJSONStringifyBeauty
+ />
+
+ )}
+
+ )
+}
+
+export default OutputPanel
diff --git a/web/i18n/en-US/run-log.ts b/web/i18n/en-US/run-log.ts
index 964076c1f4..4091bd4a39 100644
--- a/web/i18n/en-US/run-log.ts
+++ b/web/i18n/en-US/run-log.ts
@@ -1,5 +1,6 @@
const translation = {
result: 'RESULT',
+ detail: 'DETAIL',
tracing: 'TRACING',
resultPanel: {
status: 'STATUS',
diff --git a/web/i18n/zh-Hans/run-log.ts b/web/i18n/zh-Hans/run-log.ts
index 5149c92798..d5a3202657 100644
--- a/web/i18n/zh-Hans/run-log.ts
+++ b/web/i18n/zh-Hans/run-log.ts
@@ -1,5 +1,6 @@
const translation = {
result: '结果',
+ detail: '详情',
tracing: '追踪',
resultPanel: {
status: '状态',
diff --git a/web/types/workflow.ts b/web/types/workflow.ts
index 0135ea2232..0db37a9f0d 100644
--- a/web/types/workflow.ts
+++ b/web/types/workflow.ts
@@ -30,6 +30,7 @@ export type NodeTracing = {
email: string
}
finished_at: number
+ extras?: any
expand?: boolean // for UI
}
@@ -96,6 +97,7 @@ export type NodeStartedResponse = {
predecessor_node_id?: string
inputs: any
created_at: number
+ extras?: any
}
}