'use client' import type { FC } from 'react' import React, { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import { RiArrowLeftLine, RiArrowRightSLine, RiErrorWarningLine, RiLoader2Line, } from '@remixicon/react' import { NodeRunningStatus } from '@/app/components/workflow/types' import TracingPanel from '@/app/components/workflow/run/tracing-panel' import { Loop } from '@/app/components/base/icons/src/vender/workflow' import cn from '@/utils/classnames' import type { LoopDurationMap, LoopVariableMap, NodeTracing } from '@/types/workflow' import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor' import { CodeLanguage } from '@/app/components/workflow/nodes/code/types' const i18nPrefix = 'workflow.singleRun' type Props = { list: NodeTracing[][] onBack: () => void loopDurationMap?: LoopDurationMap loopVariableMap?: LoopVariableMap } const LoopResultPanel: FC = ({ list, onBack, loopDurationMap, loopVariableMap, }) => { const { t } = useTranslation() const [expandedLoops, setExpandedLoops] = useState>({}) const toggleLoop = useCallback((index: number) => { setExpandedLoops(prev => ({ ...prev, [index]: !prev[index], })) }, []) const countLoopDuration = (loop: NodeTracing[], loopDurationMap: LoopDurationMap): string => { const loopRunIndex = loop[0]?.execution_metadata?.loop_index as number const loopRunId = loop[0]?.execution_metadata?.parallel_mode_run_id const loopItem = loopDurationMap[loopRunId || loopRunIndex] const duration = loopItem return `${(duration && duration > 0.01) ? duration.toFixed(2) : 0.01}s` } const loopStatusShow = (index: number, loop: NodeTracing[], loopDurationMap?: LoopDurationMap) => { const hasFailed = loop.some(item => item.status === NodeRunningStatus.Failed) const isRunning = loop.some(item => item.status === NodeRunningStatus.Running) const hasDurationMap = loopDurationMap && Object.keys(loopDurationMap).length !== 0 if (hasFailed) return if (isRunning) return return ( <> {hasDurationMap && (
{countLoopDuration(loop, loopDurationMap)}
)} ) } return (
{ e.stopPropagation() e.nativeEvent.stopImmediatePropagation() onBack() }} >
{t(`${i18nPrefix}.back`)}
{/* List */}
{list.map((loop, index) => (
toggleLoop(index)} >
{t(`${i18nPrefix}.loop`)} {index + 1} {loopStatusShow(index, loop, loopDurationMap)}
{expandedLoops[index] &&
}
{ loopVariableMap?.[index] && (
{t('workflow.nodes.loop.loopVariables').toLocaleUpperCase()}
} language={CodeLanguage.json} height={112} value={loopVariableMap[index]} isJSONStringifyBeauty />
) }
))}
) } export default React.memo(LoopResultPanel)