import copy from 'copy-to-clipboard' import { memo, useCallback, useEffect, useState, } from 'react' import { useTranslation } from 'react-i18next' import ActionButton from '@/app/components/base/action-button' import Button from '@/app/components/base/button' import { RefreshCcw01 } from '@/app/components/base/icons/src/vender/line/arrows' import Loading from '@/app/components/base/loading' import Tooltip from '@/app/components/base/tooltip' import { submitHumanInputForm } from '@/service/workflow' import { cn } from '@/utils/classnames' import Toast from '../../base/toast' import { useWorkflowInteractions, } from '../hooks' import ResultPanel from '../run/result-panel' import ResultText from '../run/result-text' import TracingPanel from '../run/tracing-panel' import { useStore } from '../store' import { WorkflowRunningStatus, } from '../types' import { formatWorkflowRunIdentifier } from '../utils' import HumanInputFilledFormList from './human-input-filled-form-list' import HumanInputFormList from './human-input-form-list' import InputsPanel from './inputs-panel' const WorkflowPreview = () => { const { t } = useTranslation() const { handleCancelDebugAndPreviewPanel, handleClearWorkflowRunHistory } = useWorkflowInteractions() const workflowRunningData = useStore(s => s.workflowRunningData) const isListening = useStore(s => s.isListening) const showInputsPanel = useStore(s => s.showInputsPanel) const workflowCanvasWidth = useStore(s => s.workflowCanvasWidth) const panelWidth = useStore(s => s.previewPanelWidth) const setPreviewPanelWidth = useStore(s => s.setPreviewPanelWidth) const humanInputFormDataList = useStore(s => s.workflowRunningData?.humanInputFormDataList) const humanInputFilledFormDataList = useStore(s => s.workflowRunningData?.humanInputFilledFormDataList) const [userSelectedTab, setUserSelectedTab] = useState(null) const effectiveTab = (() => { if (isListening) return 'DETAIL' if (workflowRunningData) { const status = workflowRunningData.result.status const isFinishedWithoutOutput = (status === WorkflowRunningStatus.Succeeded || status === WorkflowRunningStatus.Failed) && !workflowRunningData.resultText && !workflowRunningData.result.files?.length if (status === WorkflowRunningStatus.Paused && humanInputFormDataList?.length) return 'RESULT' if (isFinishedWithoutOutput && userSelectedTab === null) return 'DETAIL' return userSelectedTab ?? 'RESULT' } if (showInputsPanel) return 'INPUT' return 'TRACING' })() const shouldShowTracingLoading = effectiveTab === 'TRACING' && !workflowRunningData?.tracing?.length && (workflowRunningData?.result?.status === WorkflowRunningStatus.Running || !workflowRunningData?.result) const handleTabChange = (tab: string) => { setUserSelectedTab(tab) } const [isResizing, setIsResizing] = useState(false) const startResizing = useCallback((e: React.MouseEvent) => { e.preventDefault() setIsResizing(true) }, []) const stopResizing = useCallback(() => { setIsResizing(false) }, []) const resize = useCallback((e: MouseEvent) => { if (isResizing) { const newWidth = window.innerWidth - e.clientX // width constraints: 400 <= width <= maxAllowed (canvas - reserved 400) const reservedCanvasWidth = 400 const maxAllowed = workflowCanvasWidth ? (workflowCanvasWidth - reservedCanvasWidth) : 1024 if (newWidth >= 400 && newWidth <= maxAllowed) setPreviewPanelWidth(newWidth) } }, [isResizing, workflowCanvasWidth, setPreviewPanelWidth]) useEffect(() => { window.addEventListener('mousemove', resize) window.addEventListener('mouseup', stopResizing) return () => { window.removeEventListener('mousemove', resize) window.removeEventListener('mouseup', stopResizing) } }, [resize, stopResizing]) const handleSubmitHumanInputForm = useCallback(async (formToken: string, formData: { inputs: Record action: string }) => { await submitHumanInputForm(formToken, formData) }, []) return (
{`${t('singleRun.testRun', { ns: 'workflow' })}${workflowRunningData ? formatWorkflowRunIdentifier(workflowRunningData.result.finished_at, t('common.running', { ns: 'workflow' })) : ''}`}
{ setUserSelectedTab(null) handleClearWorkflowRunHistory() }} >
handleCancelDebugAndPreviewPanel()}>
{showInputsPanel ? (
handleTabChange('INPUT')} > {t('input', { ns: 'runLog' })}
) : null}
{ if (!workflowRunningData) return handleTabChange('RESULT') }} > {t('result', { ns: 'runLog' })}
{ if (!workflowRunningData) return handleTabChange('DETAIL') }} > {t('detail', { ns: 'runLog' })}
{ if (!workflowRunningData) return handleTabChange('TRACING') }} > {t('tracing', { ns: 'runLog' })}
{effectiveTab === 'INPUT' && showInputsPanel ? handleTabChange('RESULT')} /> : null} {effectiveTab === 'RESULT' ? (
{humanInputFormDataList && humanInputFormDataList.length > 0 && ( )} {humanInputFilledFormDataList && humanInputFilledFormDataList.length > 0 && ( )} handleTabChange('DETAIL')} /> {(workflowRunningData?.result.status === WorkflowRunningStatus.Succeeded && workflowRunningData?.resultText && typeof workflowRunningData?.resultText === 'string') && ( )}
) : null} {effectiveTab === 'DETAIL' ? ( ) : null} {effectiveTab === 'DETAIL' && !workflowRunningData?.result ? (
) : null} {effectiveTab === 'TRACING' ? ( ) : null} {shouldShowTracingLoading ? (
) : null}
) } export default memo(WorkflowPreview)