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 && ( +
+
{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 } }